From 8bc3122311dd70eabb0020e67e850b2b7904d972 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 15 Jun 2020 15:12:43 +0200 Subject: [PATCH 01/43] ci: allow gating gha on everything but macOS In our GitHub Actions setup macOS is too unreliable to gate on it, but the other builders work fine. This commit splits the macOS builders into a separate job (called auto-fallible), allowing us to gate on the auto job without failing due to macOS spurious failures. --- .github/workflows/ci.yml | 158 ++++++++++++++++++++++++++++------- src/ci/github-actions/ci.yml | 81 ++++++++++-------- 2 files changed, 174 insertions(+), 65 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 355f282921537..7501674f48ffe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -373,35 +373,6 @@ jobs: env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json os: ubuntu-latest-xl - - name: dist-x86_64-apple - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-latest - - name: dist-x86_64-apple-alt - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - - name: x86_64-apple - env: - SCRIPT: "./x.py test" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -589,6 +560,135 @@ jobs: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" + auto-fallible: + name: auto-fallible + env: + CI_JOB_NAME: "${{ matrix.name }}" + SCCACHE_BUCKET: rust-lang-gha-caches + DEPLOY_BUCKET: rust-lang-gha + TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" + TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues" + TOOLSTATE_PUBLISH: 1 + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5 + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF + CACHE_DOMAIN: ci-caches-gha.rust-lang.org + if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" + strategy: + matrix: + include: + - name: dist-x86_64-apple + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + os: macos-latest + - name: dist-x86_64-apple-alt + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + - name: x86_64-apple + env: + SCRIPT: "./x.py test" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + timeout-minutes: 600 + runs-on: "${{ matrix.os }}" + steps: + - name: disable git crlf conversion + run: git config --global core.autocrlf false + shell: bash + - name: checkout the source code + uses: actions/checkout@v1 + with: + fetch-depth: 2 + - name: configure GitHub Actions to kill the build when outdated + uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master + with: + github_token: "${{ secrets.github_token }}" + if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" + - name: add extra environment variables + run: src/ci/scripts/setup-environment.sh + env: + EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" + if: success() && !env.SKIP_JOB + - name: decide whether to skip this job + run: src/ci/scripts/should-skip-this.sh + if: success() && !env.SKIP_JOB + - name: collect CPU statistics + run: src/ci/scripts/collect-cpu-stats.sh + if: success() && !env.SKIP_JOB + - name: show the current environment + run: src/ci/scripts/dump-environment.sh + if: success() && !env.SKIP_JOB + - name: install awscli + run: src/ci/scripts/install-awscli.sh + if: success() && !env.SKIP_JOB + - name: install sccache + run: src/ci/scripts/install-sccache.sh + if: success() && !env.SKIP_JOB + - name: install clang + run: src/ci/scripts/install-clang.sh + if: success() && !env.SKIP_JOB + - name: install WIX + run: src/ci/scripts/install-wix.sh + if: success() && !env.SKIP_JOB + - name: install InnoSetup + run: src/ci/scripts/install-innosetup.sh + if: success() && !env.SKIP_JOB + - name: ensure the build happens on a partition with enough space + run: src/ci/scripts/symlink-build-dir.sh + if: success() && !env.SKIP_JOB + - name: disable git crlf conversion + run: src/ci/scripts/disable-git-crlf-conversion.sh + if: success() && !env.SKIP_JOB + - name: install MSYS2 + run: src/ci/scripts/install-msys2.sh + if: success() && !env.SKIP_JOB + - name: install MinGW + run: src/ci/scripts/install-mingw.sh + if: success() && !env.SKIP_JOB + - name: install ninja + run: src/ci/scripts/install-ninja.sh + if: success() && !env.SKIP_JOB + - name: enable ipv6 on Docker + run: src/ci/scripts/enable-docker-ipv6.sh + if: success() && !env.SKIP_JOB + - name: disable git crlf conversion + run: src/ci/scripts/disable-git-crlf-conversion.sh + if: success() && !env.SKIP_JOB + - name: checkout submodules + run: src/ci/scripts/checkout-submodules.sh + if: success() && !env.SKIP_JOB + - name: ensure line endings are correct + run: src/ci/scripts/verify-line-endings.sh + if: success() && !env.SKIP_JOB + - name: run the build + run: src/ci/scripts/run-build-from-ci.sh + env: + AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" + AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" + TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" + if: success() && !env.SKIP_JOB + - name: upload artifacts to S3 + run: src/ci/scripts/upload-artifacts.sh + env: + AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" + AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" + if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" master: name: master runs-on: ubuntu-latest diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 590845b33cda7..6e441f8f5ad50 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -419,42 +419,6 @@ jobs: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-xl - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - ###################### # Windows Builders # ###################### @@ -606,6 +570,51 @@ jobs: SCRIPT: python x.py dist <<: *job-windows-xl + auto-fallible: + <<: *base-ci-job + name: auto-fallible + env: + <<: [*shared-ci-variables, *prod-variables] + if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' + strategy: + matrix: + include: + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + master: name: master runs-on: ubuntu-latest From 2ea386424f1a9065947a5ac246043a6945e90def Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 15 Jun 2020 18:04:43 +0100 Subject: [PATCH 02/43] Remove use of specialization from librustc_arena --- src/librustc_arena/lib.rs | 91 +++++++++++++++++--------------- src/librustc_ast_lowering/lib.rs | 2 - src/librustc_middle/lib.rs | 1 - 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/librustc_arena/lib.rs b/src/librustc_arena/lib.rs index 4a2a0de0e211f..7f154052538ac 100644 --- a/src/librustc_arena/lib.rs +++ b/src/librustc_arena/lib.rs @@ -602,7 +602,7 @@ macro_rules! which_arena_for_type { #[macro_export] macro_rules! declare_arena { - ([], [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => { + ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => { #[derive(Default)] pub struct Arena<$tcx> { pub dropless: $crate::DroplessArena, @@ -610,39 +610,56 @@ macro_rules! declare_arena { $($name: $crate::arena_for_type!($a[$ty]),)* } - #[marker] - pub trait ArenaAllocatable<'tcx> {} - - impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {} - - unsafe trait ArenaField<'tcx>: Sized + ArenaAllocatable<'tcx> { - /// Returns a specific arena to allocate from. - /// If `None` is returned, the `DropArena` will be used. - fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena>; + pub trait ArenaAllocatable<'tcx, T = Self>: Sized { + fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; + fn allocate_from_iter<'a>( + arena: &'a Arena<'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'a mut [Self]; } - unsafe impl<'tcx, T: ArenaAllocatable<'tcx>> ArenaField<'tcx> for T { + impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T { #[inline] - default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena> { - panic!() + fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { + arena.dropless.alloc(self) + } + #[inline] + fn allocate_from_iter<'a>( + arena: &'a Arena<'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'a mut [Self] { + arena.dropless.alloc_from_iter(iter) } - } + } $( - #[allow(unused_lifetimes)] - impl<$tcx> ArenaAllocatable<$tcx> for $ty {} - unsafe impl<$tcx, '_x, '_y, '_z, '_w> ArenaField<$tcx> for $gen_ty where Self: ArenaAllocatable<$tcx> { + impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty { #[inline] - fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena> { - // SAFETY: We only implement `ArenaAllocatable<$tcx>` for - // `$ty`, so `$ty` and Self are the same type - unsafe { - ::std::mem::transmute::< - Option<&'a $crate::TypedArena<$ty>>, - Option<&'a $crate::TypedArena>, - >( - $crate::which_arena_for_type!($a[&_arena.$name]) - ) + fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self { + if !::std::mem::needs_drop::() { + return arena.dropless.alloc(self); + } + match $crate::which_arena_for_type!($a[&arena.$name]) { + ::std::option::Option::<&$crate::TypedArena>::Some(ty_arena) => { + ty_arena.alloc(self) + } + ::std::option::Option::None => unsafe { arena.drop.alloc(self) }, + } + } + + #[inline] + fn allocate_from_iter<'a>( + arena: &'a Arena<$tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'a mut [Self] { + if !::std::mem::needs_drop::() { + return arena.dropless.alloc_from_iter(iter); + } + match $crate::which_arena_for_type!($a[&arena.$name]) { + ::std::option::Option::<&$crate::TypedArena>::Some(ty_arena) => { + ty_arena.alloc_from_iter(iter) + } + ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) }, } } } @@ -650,14 +667,8 @@ macro_rules! declare_arena { impl<'tcx> Arena<'tcx> { #[inline] - pub fn alloc>(&self, value: T) -> &mut T { - if !::std::mem::needs_drop::() { - return self.dropless.alloc(value); - } - match >::arena(self) { - ::std::option::Option::Some(arena) => arena.alloc(value), - ::std::option::Option::None => unsafe { self.drop.alloc(value) }, - } + pub fn alloc, U>(&self, value: T) -> &mut T { + value.allocate_on(self) } #[inline] @@ -668,17 +679,11 @@ macro_rules! declare_arena { self.dropless.alloc_slice(value) } - pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx>>( + pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>( &'a self, iter: impl ::std::iter::IntoIterator, ) -> &'a mut [T] { - if !::std::mem::needs_drop::() { - return self.dropless.alloc_from_iter(iter); - } - match >::arena(self) { - ::std::option::Option::Some(arena) => arena.alloc_from_iter(iter), - ::std::option::Option::None => unsafe { self.drop.alloc_from_iter(iter) }, - } + T::allocate_from_iter(self, iter) } } } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index a722a88a7a102..af1e33a049bfb 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -32,8 +32,6 @@ #![feature(array_value_iter)] #![feature(crate_visibility_modifier)] -#![feature(marker_trait_attr)] -#![feature(min_specialization)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs index 62c92e988ba60..2e27ab514d80b 100644 --- a/src/librustc_middle/lib.rs +++ b/src/librustc_middle/lib.rs @@ -36,7 +36,6 @@ #![feature(drain_filter)] #![feature(never_type)] #![feature(exhaustive_patterns)] -#![feature(marker_trait_attr)] #![feature(extern_types)] #![feature(nll)] #![feature(option_expect_none)] From 1b92d592b5c7f8a3d399e5b9005f4b316b316ef1 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 16 Jun 2020 19:29:53 +0100 Subject: [PATCH 03/43] Explain unused macro param --- src/librustc_arena/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_arena/lib.rs b/src/librustc_arena/lib.rs index 7f154052538ac..a21d30bf817e3 100644 --- a/src/librustc_arena/lib.rs +++ b/src/librustc_arena/lib.rs @@ -602,6 +602,10 @@ macro_rules! which_arena_for_type { #[macro_export] macro_rules! declare_arena { + // This macro has to take the same input as + // `impl_arena_allocatable_decoders` which requires a second version of + // each type. We ignore that type until we can fix + // `impl_arena_allocatable_decoders`. ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => { #[derive(Default)] pub struct Arena<$tcx> { From 936b6bfa646c90b0533cc33bbbc03d890d0780f1 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 12 Jun 2020 18:13:10 +0100 Subject: [PATCH 04/43] Move `trait_map` into `hir::Crate` --- src/librustc_ast_lowering/lib.rs | 10 ++++++++++ src/librustc_hir/hir.rs | 4 +++- src/librustc_middle/hir/map/collector.rs | 1 + src/librustc_middle/ty/context.rs | 4 ++-- src/librustc_middle/ty/mod.rs | 1 - src/librustc_resolve/lib.rs | 15 ++++----------- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index a722a88a7a102..6abf3dac76a21 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -205,6 +205,8 @@ pub trait Resolver { fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; + + fn trait_map(&self) -> &NodeMap>; } type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream; @@ -557,6 +559,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let proc_macros = c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect(); + let trait_map = self + .resolver + .trait_map() + .iter() + .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone())) + .collect(); + self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id); hir::Crate { @@ -571,6 +580,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_impls: self.trait_impls, modules: self.modules, proc_macros, + trait_map, } } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index eb1db46fd2bda..7d1cb7738c35e 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -639,6 +639,8 @@ pub struct Crate<'hir> { /// A list of proc macro HirIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. pub proc_macros: Vec, + + pub trait_map: BTreeMap>, } impl Crate<'hir> { @@ -2651,7 +2653,7 @@ pub type CaptureModeMap = NodeMap; // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. -#[derive(Clone, Debug)] +#[derive(RustcEncodable, RustcDecodable, Clone, Debug)] pub struct TraitCandidate { pub def_id: DefId, pub import_ids: SmallVec<[LocalDefId; 1]>, diff --git a/src/librustc_middle/hir/map/collector.rs b/src/librustc_middle/hir/map/collector.rs index 2906da437abac..2b3c21daa4635 100644 --- a/src/librustc_middle/hir/map/collector.rs +++ b/src/librustc_middle/hir/map/collector.rs @@ -117,6 +117,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { body_ids: _, modules: _, proc_macros: _, + trait_map: _, } = *krate; hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 6380f8be98d13..5b44ffe8cafd7 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1101,9 +1101,9 @@ impl<'tcx> TyCtxt<'tcx> { }; let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (hir_id, v) in resolutions.trait_map.into_iter() { + for (hir_id, v) in krate.trait_map.iter() { let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, StableVec::new(v)); + map.insert(hir_id.local_id, StableVec::new(v.to_vec())); } GlobalCtxt { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index ca0a1ac71c644..56fb3b58d3f6b 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -121,7 +121,6 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub extern_crate_map: FxHashMap, - pub trait_map: FxHashMap>, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub export_map: ExportMap, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 66e5612b627b4..91bd155614178 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1109,6 +1109,10 @@ impl rustc_ast_lowering::Resolver for Resolver<'_> { fn next_node_id(&mut self) -> NodeId { self.next_node_id() } + + fn trait_map(&self) -> &NodeMap> { + &self.trait_map + } } impl<'a> Resolver<'a> { @@ -1284,11 +1288,6 @@ impl<'a> Resolver<'a> { let definitions = self.definitions; let extern_crate_map = self.extern_crate_map; let export_map = self.export_map; - let trait_map = self - .trait_map - .into_iter() - .map(|(k, v)| (definitions.node_id_to_hir_id(k), v)) - .collect(); let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; @@ -1297,7 +1296,6 @@ impl<'a> Resolver<'a> { cstore: Box::new(self.crate_loader.into_cstore()), extern_crate_map, export_map, - trait_map, glob_map, maybe_unused_trait_imports, maybe_unused_extern_crates, @@ -1315,11 +1313,6 @@ impl<'a> Resolver<'a> { cstore: Box::new(self.cstore().clone()), extern_crate_map: self.extern_crate_map.clone(), export_map: self.export_map.clone(), - trait_map: self - .trait_map - .iter() - .map(|(&k, v)| (self.definitions.node_id_to_hir_id(k), v.clone())) - .collect(), glob_map: self.glob_map.clone(), maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), From a98f35f503ad4df9c6083d01447700c57436a0bc Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 12 Jun 2020 18:36:58 +0100 Subject: [PATCH 05/43] Remove `NodeId` to `HirId` conversion APIs --- src/librustc_hir/definitions.rs | 12 +----------- src/librustc_middle/hir/map/collector.rs | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index b63dd653c4dd8..679fd1668dde1 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -328,7 +328,7 @@ impl Definitions { #[inline] pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| { - panic!("no entry for node id: `{:?}` / `{:?}`", node, self.opt_node_id_to_hir_id(node)) + panic!("no entry for node id: `{:?}` / `{:?}`", node, self.node_id_to_hir_id.get(node)) }) } @@ -342,16 +342,6 @@ impl Definitions { self.hir_id_to_node_id[&hir_id] } - #[inline] - pub fn node_id_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { - self.node_id_to_hir_id[node_id].unwrap() - } - - #[inline] - pub fn opt_node_id_to_hir_id(&self, node_id: ast::NodeId) -> Option { - self.node_id_to_hir_id[node_id] - } - #[inline] pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId { let node_id = self.def_id_to_node_id[id]; diff --git a/src/librustc_middle/hir/map/collector.rs b/src/librustc_middle/hir/map/collector.rs index 2b3c21daa4635..ae169976698cc 100644 --- a/src/librustc_middle/hir/map/collector.rs +++ b/src/librustc_middle/hir/map/collector.rs @@ -243,7 +243,6 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // owner of that node. if cfg!(debug_assertions) { let node_id = self.definitions.hir_id_to_node_id(hir_id); - assert_eq!(self.definitions.node_id_to_hir_id(node_id), hir_id); if hir_id.owner != self.current_dep_node_owner { let node_str = match self.definitions.opt_local_def_id(node_id) { From 6a0f1af19d504635ea36efdf4ea68b1df935fc1b Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 12 Jun 2020 18:43:58 +0100 Subject: [PATCH 06/43] Remove `HirId` to `NodeId` conversion APIs --- src/librustc_hir/definitions.rs | 7 +------ src/librustc_middle/hir/map/collector.rs | 16 ++++------------ 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 679fd1668dde1..9913f92d2d98e 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -337,11 +337,6 @@ impl Definitions { self.local_def_id_to_hir_id(def_id) } - #[inline] - pub fn hir_id_to_node_id(&self, hir_id: hir::HirId) -> ast::NodeId { - self.hir_id_to_node_id[&hir_id] - } - #[inline] pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId { let node_id = self.def_id_to_node_id[id]; @@ -356,7 +351,7 @@ impl Definitions { #[inline] pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option { - let node_id = self.hir_id_to_node_id(hir_id); + let node_id = self.hir_id_to_node_id[&hir_id]; self.opt_local_def_id(node_id) } diff --git a/src/librustc_middle/hir/map/collector.rs b/src/librustc_middle/hir/map/collector.rs index ae169976698cc..dce06a5f7eeec 100644 --- a/src/librustc_middle/hir/map/collector.rs +++ b/src/librustc_middle/hir/map/collector.rs @@ -242,10 +242,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. if cfg!(debug_assertions) { - let node_id = self.definitions.hir_id_to_node_id(hir_id); - if hir_id.owner != self.current_dep_node_owner { - let node_str = match self.definitions.opt_local_def_id(node_id) { + let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(), None => format!("{:?}", node), }; @@ -335,9 +333,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { debug!("visit_item: {:?}", i); debug_assert_eq!( i.hir_id.owner, - self.definitions - .opt_local_def_id(self.definitions.hir_id_to_node_id(i.hir_id)) - .unwrap() + self.definitions.opt_hir_id_to_local_def_id(i.hir_id).unwrap() ); self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| { this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash); @@ -369,9 +365,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { debug_assert_eq!( ti.hir_id.owner, - self.definitions - .opt_local_def_id(self.definitions.hir_id_to_node_id(ti.hir_id)) - .unwrap() + self.definitions.opt_hir_id_to_local_def_id(ti.hir_id).unwrap() ); self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| { this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash); @@ -385,9 +379,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { debug_assert_eq!( ii.hir_id.owner, - self.definitions - .opt_local_def_id(self.definitions.hir_id_to_node_id(ii.hir_id)) - .unwrap() + self.definitions.opt_hir_id_to_local_def_id(ii.hir_id).unwrap() ); self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| { this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash); From 94817e38e14b89747c6d6d5af0d45267fcbf765e Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 12 Jun 2020 19:17:44 +0100 Subject: [PATCH 07/43] Pre-compute `hir_id_to_def_id` mapping --- src/librustc_hir/definitions.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 9913f92d2d98e..5e03395c6933e 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -87,8 +87,8 @@ pub struct Definitions { def_id_to_node_id: IndexVec, pub(super) node_id_to_hir_id: IndexVec>, - /// The reverse mapping of `node_id_to_hir_id`. - pub(super) hir_id_to_node_id: FxHashMap, + /// The pre-computed mapping of `hir_id_to_node_id` -> `node_id_to_def_id`. + pub(super) hir_id_to_def_id: FxHashMap, /// If `ExpnId` is an ID of some macro expansion, /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined. @@ -351,8 +351,7 @@ impl Definitions { #[inline] pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option { - let node_id = self.hir_id_to_node_id[&hir_id]; - self.opt_local_def_id(node_id) + self.hir_id_to_def_id.get(&hir_id).copied() } /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. @@ -467,11 +466,15 @@ impl Definitions { ); self.node_id_to_hir_id = mapping; - // Build the reverse mapping of `node_id_to_hir_id`. - self.hir_id_to_node_id = self + // Build the pre-computed mapping of `hir_id_to_node_id` -> `node_id_to_def_id`. + self.hir_id_to_def_id = self .node_id_to_hir_id .iter_enumerated() - .filter_map(|(node_id, &hir_id)| hir_id.map(|hir_id| (hir_id, node_id))) + .filter_map(|(node_id, &hir_id)| { + hir_id.and_then(|hir_id| { + self.node_id_to_def_id.get(&node_id).map(|&def_id| (hir_id, def_id)) + }) + }) .collect(); } From 51555186b680ffc63b1daf362456f7f8ca537763 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Sat, 20 Jun 2020 18:29:13 +0800 Subject: [PATCH 08/43] Decouple `Autoderef` with `FnCtxt` and move `Autoderef` to `librustc_trait_selection`. --- src/librustc_trait_selection/autoderef.rs | 229 ++++++++++++++++++ src/librustc_trait_selection/lib.rs | 1 + src/librustc_typeck/check/autoderef.rs | 246 ++------------------ src/librustc_typeck/check/callee.rs | 13 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/expr.rs | 10 +- src/librustc_typeck/check/method/confirm.rs | 7 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/place_op.rs | 9 +- src/librustc_typeck/check/wfcheck.rs | 2 +- 10 files changed, 274 insertions(+), 249 deletions(-) create mode 100644 src/librustc_trait_selection/autoderef.rs diff --git a/src/librustc_trait_selection/autoderef.rs b/src/librustc_trait_selection/autoderef.rs new file mode 100644 index 0000000000000..d542e16d83f10 --- /dev/null +++ b/src/librustc_trait_selection/autoderef.rs @@ -0,0 +1,229 @@ +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{self, TraitEngine}; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ToPredicate, TypeFoldable}; +use rustc_session::DiagnosticMessageId; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +#[derive(Copy, Clone, Debug)] +pub enum AutoderefKind { + Builtin, + Overloaded, +} + +struct AutoderefSnapshot<'tcx> { + at_start: bool, + reached_recursion_limit: bool, + steps: Vec<(Ty<'tcx>, AutoderefKind)>, + cur_ty: Ty<'tcx>, + obligations: Vec>, +} + +pub struct Autoderef<'a, 'tcx> { + // Meta infos: + infcx: &'a InferCtxt<'a, 'tcx>, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + + // Current state: + state: AutoderefSnapshot<'tcx>, + + // Configurations: + include_raw_pointers: bool, + silence_errors: bool, +} + +impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { + type Item = (Ty<'tcx>, usize); + + fn next(&mut self) -> Option { + let tcx = self.infcx.tcx; + + debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty); + if self.state.at_start { + self.state.at_start = false; + debug!("autoderef stage #0 is {:?}", self.state.cur_ty); + return Some((self.state.cur_ty, 0)); + } + + // If we have reached the recursion limit, error gracefully. + if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) { + if !self.silence_errors { + report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty); + } + self.state.reached_recursion_limit = true; + return None; + } + + if self.state.cur_ty.is_ty_var() { + return None; + } + + // Otherwise, deref if type is derefable: + let (kind, new_ty) = + if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { + (AutoderefKind::Builtin, mt.ty) + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; + + if new_ty.references_error() { + return None; + } + + self.state.steps.push((self.state.cur_ty, kind)); + debug!( + "autoderef stage #{:?} is {:?} from {:?}", + self.step_count(), + new_ty, + (self.state.cur_ty, kind) + ); + self.state.cur_ty = new_ty; + + Some((self.state.cur_ty, self.step_count())) + } +} + +impl<'a, 'tcx> Autoderef<'a, 'tcx> { + pub fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + span: Span, + base_ty: Ty<'tcx>, + ) -> Autoderef<'a, 'tcx> { + Autoderef { + infcx, + span, + body_id, + param_env, + state: AutoderefSnapshot { + steps: vec![], + cur_ty: infcx.resolve_vars_if_possible(&base_ty), + obligations: vec![], + at_start: true, + reached_recursion_limit: false, + }, + include_raw_pointers: false, + silence_errors: false, + } + } + + fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { + debug!("overloaded_deref_ty({:?})", ty); + + let tcx = self.infcx.tcx; + + // + let trait_ref = TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let cause = traits::ObligationCause::misc(self.span, self.body_id); + + let obligation = traits::Obligation::new( + cause.clone(), + self.param_env, + trait_ref.without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + debug!("overloaded_deref_ty: cannot match obligation"); + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + self.param_env, + ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")), + cause, + ); + if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { + // This shouldn't happen, except for evaluate/fulfill mismatches, + // but that's not a reason for an ICE (`predicate_may_hold` is conservative + // by design). + debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); + return None; + } + let obligations = fulfillcx.pending_obligations(); + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); + self.state.obligations.extend(obligations); + + Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) + } + + /// Returns the final type we ended up with, which may be an inference + /// variable (we will resolve it first, if we want). + pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> { + if resolve { + self.infcx.resolve_vars_if_possible(&self.state.cur_ty) + } else { + self.state.cur_ty + } + } + + pub fn step_count(&self) -> usize { + self.state.steps.len() + } + + pub fn into_obligations(self) -> Vec> { + self.state.obligations + } + + pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] { + &self.state.steps + } + + pub fn span(&self) -> Span { + self.span.clone() + } + + pub fn reached_recursion_limit(&self) -> bool { + self.state.reached_recursion_limit + } + + /// also dereference through raw pointer types + /// e.g., assuming ptr_to_Foo is the type `*const Foo` + /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo] + /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo] + pub fn include_raw_pointers(mut self) -> Self { + self.include_raw_pointers = true; + self + } + + pub fn silence_errors(mut self) -> Self { + self.silence_errors = true; + self + } +} + +pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { + // We've reached the recursion limit, error gracefully. + let suggested_limit = tcx.sess.recursion_limit() * 2; + let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); + let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); + let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + struct_span_err!( + tcx.sess, + span, + E0055, + "reached the recursion limit while auto-dereferencing `{:?}`", + ty + ) + .span_label(span, "deref recursion limit reached") + .help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, tcx.crate_name, + )) + .emit(); + } +} diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs index ea886cd1f9e9b..4692fa04ed587 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/src/librustc_trait_selection/lib.rs @@ -28,6 +28,7 @@ extern crate log; #[macro_use] extern crate rustc_middle; +pub mod autoderef; pub mod infer; pub mod opaque_types; pub mod traits; diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 2570025959cb4..97d2b3e5a8e45 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -1,191 +1,46 @@ +//! Some helper functions for `AutoDeref` use super::method::MethodCallee; use super::{FnCtxt, PlaceOp}; -use rustc_errors::struct_span_err; -use rustc_hir as hir; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::InferOk; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; -use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; -use rustc_middle::ty::{ToPredicate, TypeFoldable}; -use rustc_session::DiagnosticMessageId; -use rustc_span::symbol::Ident; +use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, TraitEngine}; +use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind}; use std::iter; -#[derive(Copy, Clone, Debug)] -enum AutoderefKind { - Builtin, - Overloaded, -} - -pub struct Autoderef<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - steps: Vec<(Ty<'tcx>, AutoderefKind)>, - cur_ty: Ty<'tcx>, - obligations: Vec>, - at_start: bool, - include_raw_pointers: bool, - span: Span, - silence_errors: bool, - reached_recursion_limit: bool, -} - -impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { - type Item = (Ty<'tcx>, usize); - - fn next(&mut self) -> Option { - let tcx = self.infcx.tcx; - - debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty); - if self.at_start { - self.at_start = false; - debug!("autoderef stage #0 is {:?}", self.cur_ty); - return Some((self.cur_ty, 0)); - } - - if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) { - if !self.silence_errors { - report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty); - } - self.reached_recursion_limit = true; - return None; - } - - if self.cur_ty.is_ty_var() { - return None; - } - - // Otherwise, deref if type is derefable: - let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers) - { - (AutoderefKind::Builtin, mt.ty) - } else { - let ty = self.overloaded_deref_ty(self.cur_ty)?; - (AutoderefKind::Overloaded, ty) - }; - - if new_ty.references_error() { - return None; - } - - self.steps.push((self.cur_ty, kind)); - debug!( - "autoderef stage #{:?} is {:?} from {:?}", - self.steps.len(), - new_ty, - (self.cur_ty, kind) - ); - self.cur_ty = new_ty; - - Some((self.cur_ty, self.steps.len())) +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { + Autoderef::new(self, self.param_env, self.body_id, span, base_ty) } -} -impl<'a, 'tcx> Autoderef<'a, 'tcx> { - pub fn new( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + pub fn try_overloaded_deref( + &self, span: Span, base_ty: Ty<'tcx>, - ) -> Autoderef<'a, 'tcx> { - Autoderef { - infcx, - body_id, - param_env, - steps: vec![], - cur_ty: infcx.resolve_vars_if_possible(&base_ty), - obligations: vec![], - at_start: true, - include_raw_pointers: false, - silence_errors: false, - reached_recursion_limit: false, - span, - } - } - - fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { - debug!("overloaded_deref_ty({:?})", ty); - - let tcx = self.infcx.tcx; - - // - let trait_ref = TraitRef { - def_id: tcx.lang_items().deref_trait()?, - substs: tcx.mk_substs_trait(ty, &[]), - }; - - let cause = traits::ObligationCause::misc(self.span, self.body_id); - - let obligation = traits::Obligation::new( - cause.clone(), - self.param_env, - trait_ref.without_const().to_predicate(tcx), - ); - if !self.infcx.predicate_may_hold(&obligation) { - debug!("overloaded_deref_ty: cannot match obligation"); - return None; - } - - let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); - let normalized_ty = fulfillcx.normalize_projection_type( - &self.infcx, - self.param_env, - ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")), - cause, - ); - if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { - // This shouldn't happen, except for evaluate/fulfill mismatches, - // but that's not a reason for an ICE (`predicate_may_hold` is conservative - // by design). - debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); - return None; - } - let obligations = fulfillcx.pending_obligations(); - debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); - self.obligations.extend(obligations); - - Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) - } - - /// Returns the final type, generating an error if it is an - /// unresolved inference variable. - pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> { - fcx.structurally_resolved_type(self.span, self.cur_ty) - } - - /// Returns the final type we ended up with, which may well be an - /// inference variable (we will resolve it first, if possible). - pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> { - self.infcx.resolve_vars_if_possible(&self.cur_ty) - } - - pub fn step_count(&self) -> usize { - self.steps.len() + ) -> Option>> { + self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) } /// Returns the adjustment steps. - pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>) -> Vec> { - fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx)) + pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec> { + self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef)) } pub fn adjust_steps_as_infer_ok( &self, - fcx: &FnCtxt<'a, 'tcx>, + autoderef: &Autoderef<'a, 'tcx>, ) -> InferOk<'tcx, Vec>> { let mut obligations = vec![]; - let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty)); - let steps: Vec<_> = self - .steps + let steps = autoderef.steps(); + let targets = + steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false))); + let steps: Vec<_> = steps .iter() .map(|&(source, kind)| { if let AutoderefKind::Overloaded = kind { - fcx.try_overloaded_deref(self.span, source).and_then( + self.try_overloaded_deref(autoderef.span(), source).and_then( |InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = method.sig.output().kind { @@ -205,67 +60,4 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { InferOk { obligations, value: steps } } - - /// also dereference through raw pointer types - /// e.g., assuming ptr_to_Foo is the type `*const Foo` - /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo] - /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo] - pub fn include_raw_pointers(mut self) -> Self { - self.include_raw_pointers = true; - self - } - - pub fn silence_errors(mut self) -> Self { - self.silence_errors = true; - self - } - - pub fn reached_recursion_limit(&self) -> bool { - self.reached_recursion_limit - } - - pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) { - fcx.register_predicates(self.into_obligations()); - } - - pub fn into_obligations(self) -> Vec> { - self.obligations - } -} - -pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { - // We've reached the recursion limit, error gracefully. - let suggested_limit = tcx.sess.recursion_limit() * 2; - let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); - let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); - let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - struct_span_err!( - tcx.sess, - span, - E0055, - "reached the recursion limit while auto-dereferencing `{:?}`", - ty - ) - .span_label(span, "deref recursion limit reached") - .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", - suggested_limit, tcx.crate_name, - )) - .emit(); - } -} - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) - } - - pub fn try_overloaded_deref( - &self, - span: Span, - base_ty: Ty<'tcx>, - ) -> Option>> { - self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) - } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index fe200a0ad2a1c..308ed5d840202 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -1,4 +1,3 @@ -use super::autoderef::Autoderef; use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; @@ -17,6 +16,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_target::spec::abi; +use rustc_trait_selection::autoderef::Autoderef; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific @@ -72,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); let output = match result { None => { @@ -106,7 +106,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], autoderef: &Autoderef<'a, 'tcx>, ) -> Option> { - let adjusted_ty = autoderef.unambiguous_final_ty(self); + let adjusted_ty = + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); debug!( "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", call_expr, adjusted_ty @@ -115,7 +116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match adjusted_ty.kind { ty::FnDef(..) | ty::FnPtr(_) => { - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(autoderef); self.apply_adjustments(callee_expr, adjustments); return Some(CallStep::Builtin(adjusted_ty)); } @@ -135,7 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &closure_sig, ) .0; - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(autoderef); self.record_deferred_call_resolution( def_id, DeferredCallResolution { @@ -176,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs)) .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None)) .map(|(autoref, method)| { - let mut adjustments = autoderef.adjust_steps(self); + let mut adjustments = self.adjust_steps(autoderef); adjustments.extend(autoref); self.apply_adjustments(callee_expr, adjustments); CallStep::Overloaded(method) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 1c34d71ee3184..7a2567d8dd229 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -422,7 +422,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let InferOk { value: mut adjustments, obligations: o } = - autoderef.adjust_steps_as_infer_ok(self); + self.adjust_steps_as_infer_ok(&autoderef); obligations.extend(o); obligations.extend(autoderef.into_obligations()); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 6a00667637155..1eaa5a6c31e20 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1447,9 +1447,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // of error recovery. self.write_field_index(expr.hir_id, index); if field.vis.is_accessible_from(def_scope, self.tcx) { - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(&autoderef); self.apply_adjustments(base, adjustments); - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span); return field_ty; @@ -1462,9 +1462,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(index) = fstr.parse::() { if fstr == index.to_string() { if let Some(field_ty) = tys.get(index) { - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(&autoderef); self.apply_adjustments(base, adjustments); - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); self.write_field_index(expr.hir_id, index); return field_ty.expect_ty(); @@ -1475,7 +1475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } - autoderef.unambiguous_final_ty(self); + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); if let Some((did, field_ty)) = private_candidate { self.ban_private_field_access(expr, expr_t, field, did); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6844c9416af8a..1c3d23a3a241f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -144,9 +144,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }; assert_eq!(n, pick.autoderefs); - let mut adjustments = autoderef.adjust_steps(self); + let mut adjustments = self.adjust_steps(&autoderef); - let mut target = autoderef.unambiguous_final_ty(self); + let mut target = + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); @@ -176,7 +177,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert!(pick.unsize.is_none()); } - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); // Write out the final adjustments. self.apply_adjustments(self.self_expr, adjustments); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index eb8f76687174e..8c4ef24b9455c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -3,7 +3,6 @@ use super::MethodError; use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; -use crate::check::autoderef::{self, Autoderef}; use crate::check::FnCtxt; use crate::hir::def::DefKind; use crate::hir::def_id::DefId; @@ -30,6 +29,7 @@ use rustc_session::config::nightly_options; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::autoderef::{self, Autoderef}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ @@ -477,7 +477,7 @@ fn method_autoderef_steps<'tcx>( }) .collect(); - let final_ty = autoderef.maybe_ambiguous_final_ty(); + let final_ty = autoderef.final_ty(true); let opt_bad_ty = match final_ty.kind { ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs index d1c22cd1ac03e..b7c8f310a1414 100644 --- a/src/librustc_typeck/check/place_op.rs +++ b/src/librustc_typeck/check/place_op.rs @@ -1,4 +1,3 @@ -use crate::check::autoderef::Autoderef; use crate::check::method::MethodCallee; use crate::check::{FnCtxt, PlaceOp}; use rustc_hir as hir; @@ -9,6 +8,7 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_trait_selection::autoderef::Autoderef; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already. @@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_index_step(expr, base_expr, &autoderef, idx_ty); } - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); result } @@ -73,7 +73,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { autoderef: &Autoderef<'a, 'tcx>, index_ty: Ty<'tcx>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let adjusted_ty = autoderef.unambiguous_final_ty(self); + let adjusted_ty = + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); debug!( "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", @@ -105,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("try_index_step: success, using overloaded indexing"); let method = self.register_infer_ok_obligations(ok); - let mut adjustments = autoderef.adjust_steps(self); + let mut adjustments = self.adjust_steps(autoderef); if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index f3297ed674347..d1a86a7ee89a8 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1118,7 +1118,7 @@ fn receiver_is_valid<'fcx, 'tcx>( ); if can_eq_self(potential_self_ty) { - autoderef.finalize(fcx); + fcx.register_predicates(autoderef.into_obligations()); if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) From ef68bf3929e5073e84b48fd76a689b071842d756 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Sat, 20 Jun 2020 18:30:12 +0800 Subject: [PATCH 09/43] Try to suggest dereferences when trait selection failed. --- .../traits/error_reporting/mod.rs | 1 + .../traits/error_reporting/suggestions.rs | 67 ++++++++++++++++++- ...trait-suggest-deferences-issue-39029.fixed | 18 +++++ .../trait-suggest-deferences-issue-39029.rs | 18 +++++ ...rait-suggest-deferences-issue-39029.stderr | 19 ++++++ ...trait-suggest-deferences-issue-62530.fixed | 15 +++++ .../trait-suggest-deferences-issue-62530.rs | 15 +++++ ...rait-suggest-deferences-issue-62530.stderr | 15 +++++ .../trait-suggest-deferences-multiple.fixed | 36 ++++++++++ .../trait-suggest-deferences-multiple.rs | 36 ++++++++++ .../trait-suggest-deferences-multiple.stderr | 15 +++++ 11 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed create mode 100644 src/test/ui/traits/trait-suggest-deferences-issue-39029.rs create mode 100644 src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr create mode 100644 src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed create mode 100644 src/test/ui/traits/trait-suggest-deferences-issue-62530.rs create mode 100644 src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr create mode 100644 src/test/ui/traits/trait-suggest-deferences-multiple.fixed create mode 100644 src/test/ui/traits/trait-suggest-deferences-multiple.rs create mode 100644 src/test/ui/traits/trait-suggest-deferences-multiple.stderr diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 060877f80adef..fd0c1a54d27ad 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -402,6 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(enclosing_scope_span, s.as_str()); } + self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index dfd7dac72d8e1..0c86e33884d6a 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -3,6 +3,7 @@ use super::{ SelectionContext, }; +use crate::autoderef::Autoderef; use crate::infer::InferCtxt; use crate::traits::normalize_projection_type; @@ -13,11 +14,11 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; -use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; +use rustc_middle::ty::{TypeAndMut, TypeckTables}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -48,6 +49,14 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, ); + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + points_at_arg: bool, + ); + fn get_closure_name( &self, def_id: DefId, @@ -450,6 +459,62 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + /// When after several dereferencing, the reference satisfies the trait + /// binding. This function provides dereference suggestion for this + /// specific situation. + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + points_at_arg: bool, + ) { + // It only make sense when suggesting dereferences for arguments + if !points_at_arg { + return; + } + let param_env = obligation.param_env; + let body_id = obligation.cause.body_id; + let span = obligation.cause.span; + let real_trait_ref = match &obligation.cause.code { + ObligationCauseCode::ImplDerivedObligation(cause) + | ObligationCauseCode::DerivedObligation(cause) + | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref, + _ => trait_ref, + }; + let real_ty = match real_trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + if let ty::Ref(region, base_ty, mutbl) = real_ty.kind { + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + if let Some(steps) = autoderef.find_map(|(ty, steps)| { + // Re-add the `&` + let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty); + Some(steps).filter(|_| self.predicate_may_hold(&obligation)) + }) { + if steps > 0 { + if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { + // Don't care about `&mut` because `DerefMut` is used less + // often and user will not expect autoderef happens. + if src.starts_with("&") { + let derefs = "*".repeat(steps); + err.span_suggestion( + span, + "consider adding dereference here", + format!("&{}{}", derefs, &src[1..]), + Applicability::MachineApplicable, + ); + } + } + } + } + } + } + /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a /// suggestion to borrow the initializer in order to use have a slice instead. fn suggest_borrow_on_unsized_slice( diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed new file mode 100644 index 0000000000000..2bb34b0ebee6f --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed @@ -0,0 +1,18 @@ +// run-rustfix +use std::net::TcpListener; + +struct NoToSocketAddrs(String); + +impl std::ops::Deref for NoToSocketAddrs { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let _works = TcpListener::bind("some string"); + let bad = NoToSocketAddrs("bad".to_owned()); + let _errors = TcpListener::bind(&*bad); + //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs new file mode 100644 index 0000000000000..33d524608a058 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs @@ -0,0 +1,18 @@ +// run-rustfix +use std::net::TcpListener; + +struct NoToSocketAddrs(String); + +impl std::ops::Deref for NoToSocketAddrs { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let _works = TcpListener::bind("some string"); + let bad = NoToSocketAddrs("bad".to_owned()); + let _errors = TcpListener::bind(&bad); + //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr new file mode 100644 index 0000000000000..0bf9794a744c9 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied + --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37 + | +LL | let _errors = TcpListener::bind(&bad); + | ^^^^ + | | + | the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | help: consider adding dereference here: `&*bad` + | + ::: $SRC_DIR/libstd/net/tcp.rs:LL:COL + | +LL | pub fn bind(addr: A) -> io::Result { + | ------------- required by this bound in `std::net::TcpListener::bind` + | + = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed new file mode 100644 index 0000000000000..fa7b9167d8d7f --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed @@ -0,0 +1,15 @@ +// run-rustfix +fn takes_str(_x: &str) {} + +fn takes_type_parameter(_x: T) where T: SomeTrait {} + +trait SomeTrait {} +impl SomeTrait for &'_ str {} +impl SomeTrait for char {} + +fn main() { + let string = String::new(); + takes_str(&string); // Ok + takes_type_parameter(&*string); // Error + //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs new file mode 100644 index 0000000000000..e785f01217735 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs @@ -0,0 +1,15 @@ +// run-rustfix +fn takes_str(_x: &str) {} + +fn takes_type_parameter(_x: T) where T: SomeTrait {} + +trait SomeTrait {} +impl SomeTrait for &'_ str {} +impl SomeTrait for char {} + +fn main() { + let string = String::new(); + takes_str(&string); // Ok + takes_type_parameter(&string); // Error + //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr new file mode 100644 index 0000000000000..9c2a582638ecb --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied + --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26 + | +LL | fn takes_type_parameter(_x: T) where T: SomeTrait {} + | --------- required by this bound in `takes_type_parameter` +... +LL | takes_type_parameter(&string); // Error + | ^^^^^^^ + | | + | the trait `SomeTrait` is not implemented for `&std::string::String` + | help: consider adding dereference here: `&*string` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple.fixed b/src/test/ui/traits/trait-suggest-deferences-multiple.fixed new file mode 100644 index 0000000000000..b7160b75c605e --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple.fixed @@ -0,0 +1,36 @@ +// run-rustfix +use std::ops::Deref; + +trait Happy {} +struct LDM; +impl Happy for &LDM {} + +struct Foo(LDM); +struct Bar(Foo); +struct Baz(Bar); +impl Deref for Foo { + type Target = LDM; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Baz { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn foo(_: T) where T: Happy {} + +fn main() { + let baz = Baz(Bar(Foo(LDM))); + foo(&***baz); + //~^ ERROR the trait bound `&Baz: Happy` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple.rs b/src/test/ui/traits/trait-suggest-deferences-multiple.rs new file mode 100644 index 0000000000000..9ac55177ffadd --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple.rs @@ -0,0 +1,36 @@ +// run-rustfix +use std::ops::Deref; + +trait Happy {} +struct LDM; +impl Happy for &LDM {} + +struct Foo(LDM); +struct Bar(Foo); +struct Baz(Bar); +impl Deref for Foo { + type Target = LDM; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Baz { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn foo(_: T) where T: Happy {} + +fn main() { + let baz = Baz(Bar(Foo(LDM))); + foo(&baz); + //~^ ERROR the trait bound `&Baz: Happy` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple.stderr new file mode 100644 index 0000000000000..f9b8bba4b4124 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&Baz: Happy` is not satisfied + --> $DIR/trait-suggest-deferences-multiple.rs:34:9 + | +LL | fn foo(_: T) where T: Happy {} + | ----- required by this bound in `foo` +... +LL | foo(&baz); + | ^^^^ + | | + | the trait `Happy` is not implemented for `&Baz` + | help: consider adding dereference here: `&***baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2e781ddacc126b24df93f7b547ced542262f12a2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 12 Jun 2020 17:42:08 +0100 Subject: [PATCH 10/43] lint: normalize projections using opaque types This commit normalizes projections which contain opaque types (opaque types are otherwise linted against, which is would have previously made the test cases added in this commit fail). Signed-off-by: David Wood --- src/librustc_lint/types.rs | 27 +++++++++++------ src/test/ui/lint/lint-ctypes-73251-1.rs | 24 ++++++++++++++++ src/test/ui/lint/lint-ctypes-73251-1.stderr | 15 ++++++++++ src/test/ui/lint/lint-ctypes-73251-2.rs | 32 +++++++++++++++++++++ src/test/ui/lint/lint-ctypes-73251-2.stderr | 15 ++++++++++ src/test/ui/lint/lint-ctypes-73251.rs | 22 ++++++++++++++ 6 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/lint/lint-ctypes-73251-1.rs create mode 100644 src/test/ui/lint/lint-ctypes-73251-1.stderr create mode 100644 src/test/ui/lint/lint-ctypes-73251-2.rs create mode 100644 src/test/ui/lint/lint-ctypes-73251-2.stderr create mode 100644 src/test/ui/lint/lint-ctypes-73251.rs diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index d92c1131ff9fd..a19c9a3557996 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -895,22 +895,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - struct ProhibitOpaqueTypes<'tcx> { + struct ProhibitOpaqueTypes<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, ty: Option>, }; - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> { + impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Opaque(..) = ty.kind { - self.ty = Some(ty); - true - } else { - ty.super_visit_with(self) + match ty.kind { + ty::Opaque(..) => { + self.ty = Some(ty); + true + } + // Consider opaque types within projections FFI-safe if they do not normalize + // to more opaque types. + ty::Projection(..) => { + let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty); + + // If `ty` is a opaque type directly then `super_visit_with` won't invoke + // this function again. + if ty.has_opaque_types() { self.visit_ty(ty) } else { false } + } + _ => ty.super_visit_with(self), } } } - let mut visitor = ProhibitOpaqueTypes { ty: None }; + let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None }; ty.visit_with(&mut visitor); if let Some(ty) = visitor.ty { self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs new file mode 100644 index 0000000000000..2ce80982f5ca1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-1.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Baz { } + +impl Baz for u32 { } + +type Qux = impl Baz; + +pub trait Foo { + type Assoc; +} + +impl Foo for u32 { + type Assoc = Qux; +} + +fn assign() -> Qux { 1 } + +extern "C" { + pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `impl Baz` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr new file mode 100644 index 0000000000000..0b4237bb96fb7 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-1.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl Baz`, which is not FFI-safe + --> $DIR/lint-ctypes-73251-1.rs:21:25 + | +LL | pub fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73251-1.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs new file mode 100644 index 0000000000000..3427c657b42ac --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-2.rs @@ -0,0 +1,32 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait TraitA { + type Assoc; +} + +impl TraitA for u32 { + type Assoc = u32; +} + +pub trait TraitB { + type Assoc; +} + +impl TraitB for T where T: TraitA { + type Assoc = ::Assoc; +} + +type AliasA = impl TraitA; + +type AliasB = impl TraitB; + +fn use_of_a() -> AliasA { 3 } + +fn use_of_b() -> AliasB { 3 } + +extern "C" { + pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `impl TraitA` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr new file mode 100644 index 0000000000000..43f7629b043a9 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl TraitA`, which is not FFI-safe + --> $DIR/lint-ctypes-73251-2.rs:29:25 + | +LL | pub fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73251-2.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73251.rs b/src/test/ui/lint/lint-ctypes-73251.rs new file mode 100644 index 0000000000000..ebc2ca77b67a1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Foo { + type Assoc; +} + +impl Foo for () { + type Assoc = u32; +} + +type Bar = impl Foo; + +fn assign() -> Bar {} + +extern "C" { + pub fn lint_me() -> ::Assoc; +} + +fn main() {} From 29272fc514ab8a05b1c228dd5800102f58999dfb Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 May 2020 17:03:32 +0100 Subject: [PATCH 11/43] Correctly handle binders inside trait predicates --- src/librustc_resolve/late/lifetimes.rs | 13 ++++++++----- .../ui/where-clauses/where-lifetime-resolution.rs | 1 - .../where-clauses/where-lifetime-resolution.stderr | 8 +------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index 5bbf8703f0b60..903eee672cf1f 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -883,7 +883,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .collect(); if !lifetimes.is_empty() { - self.trait_ref_hack = true; let next_early_index = self.next_early_index(); let scope = Scope::Binder { lifetimes, @@ -895,9 +894,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let result = self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &bound_generic_params); this.visit_ty(&bounded_ty); + this.trait_ref_hack = true; walk_list!(this, visit_param_bound, bounds); + this.trait_ref_hack = false; }); - self.trait_ref_hack = false; result } else { self.visit_ty(&bounded_ty); @@ -932,13 +932,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - if !self.trait_ref_hack + + let trait_ref_hack = take(&mut self.trait_ref_hack); + if !trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| match param.kind { GenericParamKind::Lifetime { .. } => true, _ => false, }) { - if self.trait_ref_hack { + if trait_ref_hack { struct_span_err!( self.tcx.sess, trait_ref.span, @@ -968,10 +970,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); this.visit_trait_ref(&trait_ref.trait_ref); - }) + }); } else { self.visit_trait_ref(&trait_ref.trait_ref); } + self.trait_ref_hack = trait_ref_hack; if should_pop_missing_lt { self.missing_named_lifetime_spots.pop(); } diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.rs b/src/test/ui/where-clauses/where-lifetime-resolution.rs index 0d426386768c8..d8677ee959abd 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.rs +++ b/src/test/ui/where-clauses/where-lifetime-resolution.rs @@ -7,7 +7,6 @@ fn f() where //~^ ERROR use of undeclared lifetime name `'a` for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, //~^ ERROR use of undeclared lifetime name `'b` - //~| ERROR nested quantification of lifetimes {} fn main() {} diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index 49799a93017eb..6c52664154bbf 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -7,12 +7,6 @@ LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK LL | (dyn for<'a> Trait1<'a>): Trait1<'a>, | ^^ undeclared lifetime -error[E0316]: nested quantification of lifetimes - --> $DIR/where-lifetime-resolution.rs:8:17 - | -LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, - | ^^^^^^^^^^^^^^^^^^^^^^ - error[E0261]: use of undeclared lifetime name `'b` --> $DIR/where-lifetime-resolution.rs:8:52 | @@ -22,6 +16,6 @@ LL | fn f() where LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, | ^^ undeclared lifetime -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0261`. From 04e589ced8a48818f93d6daff94a4f85e3b07271 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 May 2020 17:19:31 +0100 Subject: [PATCH 12/43] Consider fewer predicates for projection candidates We now require that projection candidates are applicable with the idenitity substs of the trait, rather than allowing predicates that are only applicable for certain substs. --- src/librustc_middle/query/mod.rs | 7 ++ src/librustc_middle/ty/subst.rs | 11 ++ .../traits/project.rs | 21 ++-- .../traits/select/mod.rs | 50 ++++----- src/librustc_ty/ty.rs | 105 +++++++++++++++++- src/librustc_typeck/check/mod.rs | 2 +- .../hr-associated-type-bound-1.rs | 18 +++ .../hr-associated-type-bound-1.stderr | 19 ++++ .../hr-associated-type-bound-2.rs | 21 ++++ .../hr-associated-type-bound-2.stderr | 13 +++ .../hr-associated-type-bound-object.rs | 14 +++ .../hr-associated-type-bound-object.stderr | 19 ++++ .../hr-associated-type-bound-param-1.rs | 20 ++++ .../hr-associated-type-bound-param-1.stderr | 19 ++++ .../hr-associated-type-bound-param-2.rs | 21 ++++ .../hr-associated-type-bound-param-2.stderr | 51 +++++++++ .../hr-associated-type-bound-param-3.rs | 21 ++++ .../hr-associated-type-bound-param-3.stderr | 19 ++++ .../hr-associated-type-bound-param-4.rs | 19 ++++ .../hr-associated-type-bound-param-4.stderr | 19 ++++ .../hr-associated-type-bound-param-5.rs | 41 +++++++ .../hr-associated-type-bound-param-5.stderr | 67 +++++++++++ .../hr-associated-type-bound-param-6.rs | 20 ++++ .../hr-associated-type-bound-param-6.stderr | 36 ++++++ .../hr-associated-type-projection-1.rs | 21 ++++ .../hr-associated-type-projection-1.stderr | 30 +++++ 26 files changed, 666 insertions(+), 38 deletions(-) create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-1.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-1.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-2.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-2.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-object.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-object.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-1.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-2.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-3.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-4.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-5.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-6.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr create mode 100644 src/test/ui/associated-types/hr-associated-type-projection-1.rs create mode 100644 src/test/ui/associated-types/hr-associated-type-projection-1.stderr diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index b3751beede25a..c88718a2761c0 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -133,6 +133,13 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + /// Returns the list of predicates that can be used for + /// `SelectionCandidate::ProjectionCandidate` and + /// `ProjectionTyCandidate::TraitDef`. + query projection_predicates(key: DefId) -> &'tcx ty::List> { + desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } + } + query native_libraries(_: CrateNum) -> Lrc> { desc { "looking up the native libraries of a linked crate" } } diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index 1529f1173b391..0cbbb95fd6fef 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -333,6 +333,17 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { /// in a different item, with `target_substs` as the base for /// the target impl/trait, with the source child-specific /// parameters (e.g., method parameters) on top of that base. + /// + /// For example given: + /// + /// trait X { fn f(); } + /// impl X for U { fn f() {} } + /// + /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait. + /// * If `source_ancestor` is the def_id of the trait. + /// * If `target_substs` is `[U]`, the substs for the impl. + /// * Then we will return `[U, T]`, the subst for `f` in the impl that + /// are needed for it to match the trait. pub fn rebase_onto( &self, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 706e68698eb55..fc689ffd96fe1 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -896,9 +896,12 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + // If so, extract what we know from the trait and try to come up with a good answer. + let bounds = match obligation_trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -908,17 +911,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( _ => return, }; - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = tcx.predicates_of(def_id); - let bounds = trait_predicates.instantiate(tcx, substs); - let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate); assemble_candidates_from_predicates( selcx, obligation, obligation_trait_ref, candidate_set, ProjectionTyCandidate::TraitDef, - bounds, + bounds.iter(), ) } @@ -1484,6 +1483,12 @@ fn confirm_impl_candidate<'cx, 'tcx>( ); return Progress { ty: tcx.ty_error(), obligations: nested }; } + // If we're trying to normalize ` as X>::A` using + //`impl X for Vec { type A = Box; }`, then: + // + // * `obligation.predicate.substs` is `[Vec, S]` + // * `substs` is `[u32]` + // * `substs` ends up as `[u32, S]` let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 3fd566eab437e..630a24752859b 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -1273,9 +1273,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_trait_predicate, ); - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + let tcx = self.infcx.tcx; + let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), _ => { span_bug!( obligation.cause.span, @@ -1285,32 +1288,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } }; - debug!( - "match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs - ); - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!( - "match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds - ); - - let elaborated_predicates = - util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter()); - let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { - self.infcx.probe(|_| { - self.match_projection( - obligation, - *bound, - placeholder_trait_predicate.trait_ref, - &placeholder_map, - snapshot, - ) - }) + let matching_bound = predicates.iter().find_map(|bound| { + if let ty::PredicateKind::Trait(bound, _) = bound.kind() { + let bound = bound.to_poly_trait_ref(); + if self.infcx.probe(|_| { + self.match_projection( + obligation, + bound, + placeholder_trait_predicate.trait_ref, + &placeholder_map, + snapshot, + ) + }) { + return Some(bound); + } + } + None }); debug!( diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index cf70a845af0aa..dd35202616366 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -1,8 +1,10 @@ use rustc_data_structures::svh::Svh; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_infer::traits::util; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; @@ -365,6 +367,106 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { fn_like.asyncness() } +/// For associated types we allow bounds written on the associated type +/// (`type X: Trait`) to be used as candidates. We also allow the same bounds +/// when desugared as bounds on the trait `where Self::X: Trait`. +/// +/// Note that this filtering is done with the trait's identity substs to +/// simplify checking that these bounds are met in impls. This means that +/// a bound such as `for<'b> >::U: Clone` can't be used, as in +/// `hr-associated-type-bound-1.rs`. +fn associated_type_projection_predicates( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> &'_ ty::List> { + let trait_id = tcx.associated_item(def_id).container.id(); + let trait_substs = InternalSubsts::identity_for_item(tcx, trait_id); + + let generic_trait_bounds = tcx.predicates_of(trait_id); + let trait_bounds = generic_trait_bounds.instantiate_identity(tcx); + let trait_predicates = util::elaborate_predicates(tcx, trait_bounds.predicates.into_iter()); + + let predicates = trait_predicates.filter_map(|obligation| { + let pred = obligation.predicate; + match pred.kind() { + ty::PredicateKind::Trait(tr, _) => { + if let ty::Projection(p) = tr.skip_binder().self_ty().kind { + if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + return Some(pred); + } + } + } + ty::PredicateKind::Projection(proj) => { + if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind { + if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + return Some(pred); + } + } + } + _ => {} + } + None + }); + + let result = tcx.mk_predicates(predicates); + debug!("associated_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + result +} + +/// Opaque types don't have the same issues as associated types: the only +/// predicates on an opaque type (excluding those it inherits from its parent +/// item) should be of the form we're expecting. +fn opaque_type_projection_predicates( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> &'_ ty::List> { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + + let generics_bounds = tcx.predicates_of(def_id); + let bounds = generics_bounds.instantiate_identity(tcx); + let predicates = util::elaborate_predicates(tcx, bounds.predicates.into_iter()); + + let filtered_predicates = predicates.filter_map(|obligation| { + let pred = obligation.predicate; + match pred.kind() { + ty::PredicateKind::Trait(tr, _) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = tr.skip_binder().self_ty().kind { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } + } + ty::PredicateKind::Projection(proj) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = + proj.skip_binder().projection_ty.self_ty().kind + { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } + } + _ => {} + } + tcx.sess.delay_span_bug( + obligation.cause.span(tcx), + &format!("unexpected predicate {:?} on opaque type", pred), + ); + None + }); + + let result = tcx.mk_predicates(filtered_predicates); + debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + result +} + +fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List> { + match tcx.def_kind(def_id) { + DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id), + DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id), + k => bug!("projection_predicates called on {}", k.descr(def_id)), + } +} + pub fn provide(providers: &mut ty::query::Providers<'_>) { *providers = ty::query::Providers { asyncness, @@ -381,6 +483,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, + projection_predicates, ..*providers }; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 775441cb74666..1594d65e9bdee 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2281,7 +2281,7 @@ fn check_impl_items_against_trait<'tcx>( &ty_trait_item, impl_trait_ref, opt_trait_span, - ) + ); } else { let mut err = struct_span_err!( tcx.sess, diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs new file mode 100644 index 0000000000000..497b86eeab88d --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.rs @@ -0,0 +1,18 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(&self, x: &Self::U) { + ::clone(x); + } +} + +impl X<'_> for i32 { + type U = str; + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` +} + +fn main() { + 1i32.f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr new file mode 100644 index 0000000000000..7ef2faef9c6e7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-1.rs:12:14 + | +LL | trait X<'a> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-2.rs new file mode 100644 index 0000000000000..7ff0fede28cfe --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.rs @@ -0,0 +1,21 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(&self, x: &Self::U) { + ::clone(x); + } +} + +impl X<'_> for u32 +where + for<'b> >::U: Clone, +{ + type U = str; +} + +fn main() { + 1u32.f("abc"); + //~^ ERROR no method named `f` found for type `u32` in the current scope +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr new file mode 100644 index 0000000000000..2a364d349d77e --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `f` found for type `u32` in the current scope + --> $DIR/hr-associated-type-bound-2.rs:19:10 + | +LL | 1u32.f("abc"); + | ^ method not found in `u32` + | + = note: the method `f` exists but the following trait bounds were not satisfied: + `>::U: std::clone::Clone` + which is required by `u32: X` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs new file mode 100644 index 0000000000000..7c64ae38caf60 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.rs @@ -0,0 +1,14 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; +} +fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + <>::U>::clone(x); +} + +pub fn main() { + f::>("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr new file mode 100644 index 0000000000000..db966875c708f --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-object.rs:7:13 + | +LL | trait X<'a> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { + | ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs new file mode 100644 index 0000000000000..a65f8a8c498b7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs @@ -0,0 +1,20 @@ +trait Y<'a, T: ?Sized> +where + T: Y<'a, Self>, + for<'b> >::V: Clone, + for<'b> >::V: Clone, +{ + type V: ?Sized; + fn g(&self, x: &Self::V) { + ::clone(x); + } +} + +impl<'a> Y<'a, u8> for u8 { + type V = str; + //~^ ERROR the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied +} + +fn main() { + 1u8.g("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr new file mode 100644 index 0000000000000..347a5818dce31 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-1.rs:14:14 + | +LL | trait Y<'a, T: ?Sized> + | - required by a bound in this +... +LL | for<'b> >::V: Clone, + | ----- required by this bound in `Y` +... +LL | type V = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::V` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs new file mode 100644 index 0000000000000..9f849b0327669 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -0,0 +1,21 @@ +trait Z<'a, T: ?Sized> +where + T: Z<'a, u16>, + //~^ the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + //~| the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + for<'b> >::W: Clone, +{ + type W: ?Sized; + fn h(&self, x: &T::W) { + ::clone(x); + } +} + +impl<'a> Z<'a, u16> for u16 { + type W = str; + //~^ ERROR the trait bound `for<'b> >::W: std::clone::Clone +} + +fn main() { + 1u16.h("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr new file mode 100644 index 0000000000000..e06777e36a8c5 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -0,0 +1,51 @@ +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +LL | where +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:15:14 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` +... +LL | type W = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +LL | where +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs new file mode 100644 index 0000000000000..9aca59f8ce6d7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +trait X<'a, T> +where + for<'b> T: X<'b, T>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, (T,)> for (S,) { + type U = str; + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X<(i32,)>>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr new file mode 100644 index 0000000000000..ff56f60e4c9e5 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-3.rs:15:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs new file mode 100644 index 0000000000000..ffe43c674c3dc --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs @@ -0,0 +1,19 @@ +trait X<'a, T> +where + for<'b> (T,): X<'b, T>, + for<'b> <(T,) as X<'b, T>>::U: Clone, +{ + type U: ?Sized; + fn f(x: &<(T,) as X<'_, T>>::U) { + <<(T,) as X<'_, T>>::U>::clone(x); + } +} + +impl X<'_, T> for (S,) { + type U = str; + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr new file mode 100644 index 0000000000000..c41efb8b6e1a2 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-4.rs:13:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> <(T,) as X<'b, T>>::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs new file mode 100644 index 0000000000000..dcca0b3ce92aa --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs @@ -0,0 +1,41 @@ +// ignore-tidy-linelength + +trait Cycle: Sized { + type Next: Cycle; +} + +impl Cycle for Box { + type Next = Vec; +} + +impl Cycle for Vec { + type Next = Box; +} + +trait X<'a, T: Cycle + for<'b> X<'b, T>> +where + for<'b> >::U: Clone, + for<'b> T::Next: X<'b, T::Next>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, Vec> for S { + type U = str; + //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied +} + +impl X<'_, Box> for S { + type U = str; + //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + >>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr new file mode 100644 index 0000000000000..39c191e974777 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:28:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:28:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:34:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:34:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs new file mode 100644 index 0000000000000..4b8018cb43024 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs @@ -0,0 +1,20 @@ +trait X<'a, T> +where + for<'b> T: X<'b, T>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, T> for (S,) { + //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied + type U = str; + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr new file mode 100644 index 0000000000000..83845d3a9410e --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -0,0 +1,36 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:14:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:12:12 + | +LL | trait X<'a, T> + | - required by a bound in this +LL | where +LL | for<'b> T: X<'b, T>, + | -------- required by this bound in `X` +... +LL | impl X<'_, T> for (S,) { + | ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl X<'b, T>> X<'_, T> for (S,) { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs new file mode 100644 index 0000000000000..0d4567a55fc99 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.rs @@ -0,0 +1,21 @@ +trait UnsafeCopy<'a, T: Copy> +where + for<'b> >::Item: std::ops::Deref, +{ + type Item; + + fn bug(item: &Self::Item) -> () { + let x: T = **item; + &x as *const _; + } +} + +impl UnsafeCopy<'_, T> for T { + //~^ ERROR the trait bound `>::Item: std::ops::Deref` is not satisfied + type Item = T; + //~^ ERROR the trait bound `for<'b> >::Item: std::ops::Deref +} + +pub fn main() { + <&'static str>::bug(&""); +} diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr new file mode 100644 index 0000000000000..5ab57410c441b --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `for<'b> >::Item: std::ops::Deref` is not satisfied + --> $DIR/hr-associated-type-projection-1.rs:15:17 + | +LL | trait UnsafeCopy<'a, T: Copy> + | ---------- required by a bound in this +LL | where +LL | for<'b> >::Item: std::ops::Deref, + | --------------------------- required by this bound in `UnsafeCopy` +... +LL | type Item = T; + | ^ the trait `for<'b> std::ops::Deref` is not implemented for `>::Item` + | + = help: the following implementations were found: + <&T as std::ops::Deref> + <&mut T as std::ops::Deref> + +error[E0277]: the trait bound `>::Item: std::ops::Deref` is not satisfied + --> $DIR/hr-associated-type-projection-1.rs:13:33 + | +LL | impl UnsafeCopy<'_, T> for T { + | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `>::Item` + | +help: consider further restricting the associated type + | +LL | impl UnsafeCopy<'_, T> for T where >::Item: std::ops::Deref { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From f1e07103d3ebac4e820311254e077481d00bed49 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Sat, 20 Jun 2020 20:00:36 +0800 Subject: [PATCH 13/43] Prevent incorrect help message for dereference suggestion --- .../traits/error_reporting/suggestions.rs | 2 +- ...trait-suggest-deferences-multiple-0.fixed} | 0 ...=> trait-suggest-deferences-multiple-0.rs} | 0 ...rait-suggest-deferences-multiple-0.stderr} | 2 +- .../trait-suggest-deferences-multiple-1.rs | 54 +++++++++++++++++++ ...trait-suggest-deferences-multiple-1.stderr | 12 +++++ 6 files changed, 68 insertions(+), 2 deletions(-) rename src/test/ui/traits/{trait-suggest-deferences-multiple.fixed => trait-suggest-deferences-multiple-0.fixed} (100%) rename src/test/ui/traits/{trait-suggest-deferences-multiple.rs => trait-suggest-deferences-multiple-0.rs} (100%) rename src/test/ui/traits/{trait-suggest-deferences-multiple.stderr => trait-suggest-deferences-multiple-0.stderr} (89%) create mode 100644 src/test/ui/traits/trait-suggest-deferences-multiple-1.rs create mode 100644 src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 0c86e33884d6a..176bd90303ddd 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -500,7 +500,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { // Don't care about `&mut` because `DerefMut` is used less // often and user will not expect autoderef happens. - if src.starts_with("&") { + if src.starts_with("&") && !src.starts_with("&mut ") { let derefs = "*".repeat(steps); err.span_suggestion( span, diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple.fixed b/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed similarity index 100% rename from src/test/ui/traits/trait-suggest-deferences-multiple.fixed rename to src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs similarity index 100% rename from src/test/ui/traits/trait-suggest-deferences-multiple.rs rename to src/test/ui/traits/trait-suggest-deferences-multiple-0.rs diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr similarity index 89% rename from src/test/ui/traits/trait-suggest-deferences-multiple.stderr rename to src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr index f9b8bba4b4124..add34a553bc9f 100644 --- a/src/test/ui/traits/trait-suggest-deferences-multiple.stderr +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&Baz: Happy` is not satisfied - --> $DIR/trait-suggest-deferences-multiple.rs:34:9 + --> $DIR/trait-suggest-deferences-multiple-0.rs:34:9 | LL | fn foo(_: T) where T: Happy {} | ----- required by this bound in `foo` diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs new file mode 100644 index 0000000000000..91c6c7924a408 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs @@ -0,0 +1,54 @@ +use std::ops::{Deref, DerefMut}; + +trait Happy {} +struct LDM; +impl Happy for &mut LDM {} + +struct Foo(LDM); +struct Bar(Foo); +struct Baz(Bar); +impl Deref for Foo { + type Target = LDM; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Baz { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Baz { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + + +fn foo(_: T) where T: Happy {} + +fn main() { + // Currently the compiler doesn't try to suggest dereferences for situations + // where DerefMut involves. So this test is meant to ensure compiler doesn't + // generate incorrect help message. + let mut baz = Baz(Bar(Foo(LDM))); + foo(&mut baz); + //~^ ERROR the trait bound `&mut Baz: Happy` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr new file mode 100644 index 0000000000000..e90278fa16f0e --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `&mut Baz: Happy` is not satisfied + --> $DIR/trait-suggest-deferences-multiple-1.rs:52:9 + | +LL | fn foo(_: T) where T: Happy {} + | ----- required by this bound in `foo` +... +LL | foo(&mut baz); + | ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 13104ef1c5c7e8ebd973b07b33ac3794fc8fed59 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 12 Jun 2020 19:56:16 +0100 Subject: [PATCH 14/43] Pre-compute `def_id_to_hir_id` table --- src/librustc_hir/definitions.rs | 37 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 5e03395c6933e..5755a3db92ac1 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -81,13 +81,12 @@ pub struct Definitions { def_id_to_span: IndexVec, - // FIXME(eddyb) don't go through `ast::NodeId` to convert between `HirId` - // and `LocalDefId` - ideally all `LocalDefId`s would be HIR owners. node_id_to_def_id: FxHashMap, def_id_to_node_id: IndexVec, - pub(super) node_id_to_hir_id: IndexVec>, - /// The pre-computed mapping of `hir_id_to_node_id` -> `node_id_to_def_id`. + // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners. + pub(super) def_id_to_hir_id: IndexVec>, + /// The reverse mapping of `def_id_to_hir_id`. pub(super) hir_id_to_def_id: FxHashMap, /// If `ExpnId` is an ID of some macro expansion, @@ -327,9 +326,7 @@ impl Definitions { #[inline] pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap_or_else(|| { - panic!("no entry for node id: `{:?}` / `{:?}`", node, self.node_id_to_hir_id.get(node)) - }) + self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) } #[inline] @@ -339,14 +336,12 @@ impl Definitions { #[inline] pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId { - let node_id = self.def_id_to_node_id[id]; - self.node_id_to_hir_id[node_id].unwrap() + self.def_id_to_hir_id[id].unwrap() } #[inline] pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option { - let node_id = self.def_id_to_node_id[id]; - self.node_id_to_hir_id[node_id] + self.def_id_to_hir_id[id] } #[inline] @@ -461,16 +456,20 @@ impl Definitions { mapping: IndexVec>, ) { assert!( - self.node_id_to_hir_id.is_empty(), - "trying to initialize `NodeId` -> `HirId` mapping twice" + self.def_id_to_hir_id.is_empty(), + "trying to initialize `LocalDefId` <-> `HirId` mappings twice" ); - self.node_id_to_hir_id = mapping; - // Build the pre-computed mapping of `hir_id_to_node_id` -> `node_id_to_def_id`. - self.hir_id_to_def_id = self - .node_id_to_hir_id - .iter_enumerated() - .filter_map(|(node_id, &hir_id)| { + self.def_id_to_hir_id = self + .def_id_to_node_id + .iter() + .map(|&node_id| mapping.get(node_id).and_then(|&hir_id| hir_id)) + .collect(); + + // Build the reverse mapping of `def_id_to_hir_id`. + self.hir_id_to_def_id = mapping + .into_iter_enumerated() + .filter_map(|(node_id, hir_id)| { hir_id.and_then(|hir_id| { self.node_id_to_def_id.get(&node_id).map(|&def_id| (hir_id, def_id)) }) From d660dbc630b1678fadfdd60c4d8e96d3de724b0d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 May 2020 17:21:25 +0100 Subject: [PATCH 15/43] Check associated type satisfy their bounds This was currently only happening due to eager normalization, which isn't possible if there's specialization or bound variables. --- src/librustc_typeck/check/compare_method.rs | 158 +++++++++++++++++- .../issue-68641-check-gat-bounds.rs | 32 ++++ .../issue-68641-check-gat-bounds.stderr | 26 +++ .../issue-68642-broken-llvm-ir.rs | 21 +++ .../issue-68642-broken-llvm-ir.stderr | 28 ++++ .../issue-68643-broken-mir.rs | 21 +++ .../issue-68643-broken-mir.stderr | 28 ++++ .../issue-68644-codegen-selection.rs | 21 +++ .../issue-68644-codegen-selection.stderr | 28 ++++ .../issue-68645-codegen-fulfillment.rs | 21 +++ .../issue-68645-codegen-fulfillment.stderr | 28 ++++ .../issue-68656-unsized-values.rs | 22 +++ .../issue-68656-unsized-values.stderr | 30 ++++ src/test/ui/issues/issue-38091.rs | 2 +- src/test/ui/issues/issue-38091.stderr | 12 +- .../deafult-associated-type-bound-1.rs | 24 +++ .../deafult-associated-type-bound-1.stderr | 21 +++ .../deafult-associated-type-bound-2.rs | 22 +++ .../deafult-associated-type-bound-2.stderr | 23 +++ .../deafult-generic-associated-type-bound.rs | 27 +++ ...afult-generic-associated-type-bound.stderr | 36 ++++ 21 files changed, 625 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs create mode 100644 src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs create mode 100644 src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68643-broken-mir.rs create mode 100644 src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs create mode 100644 src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs create mode 100644 src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68656-unsized-values.rs create mode 100644 src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-1.rs create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-1.stderr create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-2.rs create mode 100644 src/test/ui/specialization/deafult-associated-type-bound-2.stderr create mode 100644 src/test/ui/specialization/deafult-generic-associated-type-bound.rs create mode 100644 src/test/ui/specialization/deafult-generic-associated-type-bound.stderr diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index b39cfcb377595..98c341f4bed41 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -4,15 +4,17 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::util::ExplicitSelf; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use super::{potentially_plural_count, FnCtxt, Inherited}; +use std::iter; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -1057,13 +1059,15 @@ crate fn compare_ty_impl<'tcx>( let _: Result<(), ErrorReported> = (|| { compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?; - compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref) + compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?; + + compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref) })(); } /// The equivalent of [compare_predicate_entailment], but for associated types /// instead of associated functions. -fn compare_type_predicate_entailment( +fn compare_type_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: &ty::AssocItem, impl_ty_span: Span, @@ -1165,6 +1169,152 @@ fn compare_type_predicate_entailment( }) } +/// Validate that `ProjectionCandidate`s created for this associated type will +/// be valid. +/// +/// Usually given +/// +/// trait X { type Y: Copy } impl X for T { type Y = S; } +/// +/// We are able to normalize `::U` to `S`, and so when we check the +/// impl is well-formed we have to prove `S: Copy`. +/// +/// For default associated types the normalization is not possible (the value +/// from the impl could be overridden). We also can't normalize generic +/// associated types (yet) because they contain bound parameters. +fn compare_projection_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: &ty::AssocItem, + impl_ty: &ty::AssocItem, + impl_ty_span: Span, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorReported> { + let is_gat = !tcx.generics_of(impl_ty.def_id).params.is_empty(); + if impl_ty.defaultness.is_final() && !is_gat { + // For "final", non-generic associate type implementations, we + // don't need this as described above. + return Ok(()); + } + + let param_env = tcx.param_env(impl_ty.def_id); + + let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.container.id()); + let impl_ty_value = tcx.type_of(impl_ty.def_id); + + // Map the predicate from the trait to the corresponding one for the impl. + // For example: + // + // trait X { type Y<'a>: PartialEq } impl X for T { type Y<'a> = &'a S; } + // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; } + // + // For the `for<'a> <>::Y<'a>: PartialEq` bound, this + // function would translate and partially normalize + // `[>::Y<'a>, A]` to `[&'a u32, &'x u32]`. + let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { + let normalized_self = if !is_gat { + // projection_predicates only includes projections where the + // substs of the trait ref are exactly the trait's identity + // substs, so we can simply return the value from the impl. + impl_ty_value + } else { + let predicate_self_ty = predicate_substs.type_at(0); + let impl_ty_substs = if let ty::Projection(p) = predicate_self_ty.kind { + assert!( + p.item_def_id == trait_ty.def_id, + "projection_predicates returned predicate for the wrong type: {}", + predicate_self_ty, + ); + p.substs.rebase_onto(tcx, impl_trait_ref.def_id, impl_substs) + } else { + bug!( + "projection_predicates returned predicate for the wrong type `{}`", + predicate_self_ty, + ); + }; + impl_ty_value.subst(tcx, impl_ty_substs) + }; + + tcx.mk_substs( + iter::once(normalized_self.into()) + .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, impl_trait_ref.substs))), + ) + }; + + tcx.infer_ctxt().enter(move |infcx| { + let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); + let infcx = &inh.infcx; + let mut selcx = traits::SelectionContext::new(&infcx); + + let impl_ty_hir_id = tcx.hir().as_local_hir_id(impl_ty.def_id.expect_local()); + let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); + let cause = ObligationCause::new( + impl_ty_span, + impl_ty_hir_id, + ObligationCauseCode::ItemObligation(trait_ty.def_id), + ); + + let predicates = tcx.projection_predicates(trait_ty.def_id); + + debug!("compare_projection_bounds: projection_predicates={:?}", predicates); + + for predicate in predicates { + let concrete_ty_predicate = match predicate.kind() { + ty::PredicateKind::Trait(poly_tr, c) => poly_tr + .map_bound(|tr| { + let trait_substs = translate_predicate_substs(tr.trait_ref.substs); + ty::TraitRef { def_id: tr.def_id(), substs: trait_substs } + }) + .with_constness(*c) + .to_predicate(tcx), + ty::PredicateKind::Projection(poly_projection) => poly_projection + .map_bound(|projection| { + let projection_substs = + translate_predicate_substs(projection.projection_ty.substs); + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: projection_substs, + item_def_id: projection.projection_ty.item_def_id, + }, + ty: projection.ty.subst(tcx, impl_trait_ref.substs), + } + }) + .to_predicate(tcx), + _ => bug!("unexepected projection predicate kind: `{:?}`", predicate), + }; + + let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( + &mut selcx, + param_env, + normalize_cause.clone(), + &concrete_ty_predicate, + ); + + debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); + + inh.register_predicates(obligations); + inh.register_predicate(traits::Obligation::new( + cause.clone(), + param_env, + normalized_predicate, + )); + } + + // Check that all obligations are satisfied by the implementation's + // version. + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(errors, None, false); + return Err(ErrorReported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]); + + Ok(()) + }) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs new file mode 100644 index 0000000000000..71f9b2967dc58 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs @@ -0,0 +1,32 @@ +// Regression test for #68641 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait UnsafeCopy { + type Item<'a>: Copy; + + fn copy<'a>(item: &Self::Item<'a>) -> Self::Item<'a> { + *item + } +} + +impl UnsafeCopy for T { + type Item<'a> = T; + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied +} + +fn main() { + let mut s = String::from("Hello world!"); + + let copy = String::copy(&s); + + // Do we indeed point to the samme memory? + assert!(s.as_ptr() == copy.as_ptr()); + + // Any use of `copy` is certeinly UB after this + drop(s); + + // UB UB UB UB UB!! + println!("{}", copy); +} diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr new file mode 100644 index 0000000000000..eeff7c340ac96 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -0,0 +1,26 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68641-check-gat-bounds.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-68641-check-gat-bounds.rs:15:5 + | +LL | trait UnsafeCopy { + | ---------------- required by `UnsafeCopy` +... +LL | type Item<'a> = T; + | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs new file mode 100644 index 0000000000000..c99073c13284d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -0,0 +1,21 @@ +// Regression test for #68642 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + usize>::callme(|| 1); +} diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr new file mode 100644 index 0000000000000..b3d4b8d465180 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68642-broken-llvm-ir.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs new file mode 100644 index 0000000000000..24133e75cccee --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -0,0 +1,21 @@ +// Regression test for #68643 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +pub fn main() { + ::callme(|| {}); +} diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr new file mode 100644 index 0000000000000..6e23fe02de8cd --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68643-broken-mir.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68643-broken-mir.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs new file mode 100644 index 0000000000000..22620c61b8390 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -0,0 +1,21 @@ +// Regression test for #68644 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + ::callme(0); +} diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr new file mode 100644 index 0000000000000..234f5c8a0cc02 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68644-codegen-selection.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68644-codegen-selection.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs new file mode 100644 index 0000000000000..423b80e8476f4 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -0,0 +1,21 @@ +// Regression test for #68645 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + <&dyn Iterator>::callme(&std::iter::once(1)); +} diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr new file mode 100644 index 0000000000000..ac2d5063fbb5d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68645-codegen-fulfillment.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 + | +LL | trait Fun { + | --------- required by `Fun` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs new file mode 100644 index 0000000000000..4ccd42ba6432d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs @@ -0,0 +1,22 @@ +// Regression test for #68656 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait UnsafeCopy { + type Item<'a>: std::ops::Deref; + + fn bug<'a>(item: &Self::Item<'a>) -> () { + let x: T = **item; + &x as *const _; + } +} + +impl UnsafeCopy for T { + type Item<'a> = T; + //~^ ERROR type mismatch resolving `::Target == T` +} + +fn main() { + <&'static str>::bug(&""); +} diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr new file mode 100644 index 0000000000000..e4eb7991f7637 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -0,0 +1,30 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68656-unsized-values.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0271]: type mismatch resolving `::Target == T` + --> $DIR/issue-68656-unsized-values.rs:16:5 + | +LL | trait UnsafeCopy { + | ------------------------- required by `UnsafeCopy` +... +LL | impl UnsafeCopy for T { + | - this type parameter +LL | type Item<'a> = T; + | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type + | + = note: expected type parameter `T` + found associated type `::Target` +help: consider further restricting this bound + | +LL | impl> UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-38091.rs b/src/test/ui/issues/issue-38091.rs index c126243050244..a84391b94d1de 100644 --- a/src/test/ui/issues/issue-38091.rs +++ b/src/test/ui/issues/issue-38091.rs @@ -1,4 +1,3 @@ -// run-pass #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete @@ -8,6 +7,7 @@ trait Iterate<'a> { } impl<'a, T> Iterate<'a> for T where T: Check { default type Ty = (); + //~^ ERROR the trait bound `(): Valid` is not satisfied default fn iterate(self) {} } diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr index a9855445f6668..4d3369c5b6486 100644 --- a/src/test/ui/issues/issue-38091.stderr +++ b/src/test/ui/issues/issue-38091.stderr @@ -7,5 +7,15 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -warning: 1 warning emitted +error[E0277]: the trait bound `(): Valid` is not satisfied + --> $DIR/issue-38091.rs:8:5 + | +LL | trait Iterate<'a> { + | ----------------- required by `Iterate` +... +LL | default type Ty = (); + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()` + +error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs new file mode 100644 index 0000000000000..272a5e3fe10c6 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs @@ -0,0 +1,24 @@ +// Check that we check that default associated types satisfy the required +// bounds on them. + +#![feature(specialization)] +//~^ WARNING `specialization` is incomplete + +trait X { + type U: Clone; + fn unsafe_clone(&self, x: Option<&Self::U>) { + x.cloned(); + } +} + +// We cannot normalize `::U` to `str` here, because the default could +// be overridden. The error here must therefore be found by a method other than +// normalization. +impl X for T { + default type U = str; + //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied +} + +pub fn main() { + 1.unsafe_clone(None); +} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr new file mode 100644 index 0000000000000..8b3d6a913a7a0 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-associated-type-bound-1.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + +error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied + --> $DIR/deafult-associated-type-bound-1.rs:18:5 + | +LL | trait X { + | ------- required by `X` +... +LL | default type U = str; + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/deafult-associated-type-bound-2.rs new file mode 100644 index 0000000000000..0a21b1f09106b --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.rs @@ -0,0 +1,22 @@ +// Check that generic predicates are also checked for default associated types. +#![feature(specialization)] +//~^ WARNING `specialization` is incomplete + +trait X { + type U: PartialEq; + fn unsafe_compare(x: Option, y: Option) { + match (x, y) { + (Some(a), Some(b)) => a == b, + _ => false, + }; + } +} + +impl X for T { + default type U = &'static B; + //~^ ERROR can't compare `&'static B` with `B` +} + +pub fn main() { + >::unsafe_compare(None, None); +} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr new file mode 100644 index 0000000000000..4d21f47051fab --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -0,0 +1,23 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-associated-type-bound-2.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + +error[E0277]: can't compare `&'static B` with `B` + --> $DIR/deafult-associated-type-bound-2.rs:16:5 + | +LL | trait X { + | ---------- required by `X` +... +LL | default type U = &'static B; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `&'static B` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs new file mode 100644 index 0000000000000..8a94ea658d2d0 --- /dev/null +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs @@ -0,0 +1,27 @@ +// Check that default generics associated types are validated. + +#![feature(specialization)] +#![feature(generic_associated_types)] +//~^^ WARNING `specialization` is incomplete +//~^^ WARNING the feature `generic_associated_types` is incomplete + +trait X { + type U<'a>: PartialEq<&'a Self>; + fn unsafe_compare<'b>(x: Option>, y: Option<&'b Self>) { + match (x, y) { + (Some(a), Some(b)) => a == b, + _ => false, + }; + } +} + +impl X for T { + default type U<'a> = &'a T; + //~^ ERROR can't compare `T` with `T` +} + +struct NotComparable; + +pub fn main() { + ::unsafe_compare(None, None); +} diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr new file mode 100644 index 0000000000000..1aac9e70d87d8 --- /dev/null +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -0,0 +1,36 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-generic-associated-type-bound.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-generic-associated-type-bound.rs:4:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #44265 for more information + +error[E0277]: can't compare `T` with `T` + --> $DIR/deafult-generic-associated-type-bound.rs:19:5 + | +LL | trait X { + | ------- required by `X` +... +LL | default type U<'a> = &'a T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `T` + = note: required because of the requirements on the impl of `for<'a> std::cmp::PartialEq` for `&'a T` +help: consider further restricting this bound + | +LL | impl X for T { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0277`. From 9818bc08d314708da38d1f67b6de75c60a3a6ebf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Jun 2020 09:48:56 +0100 Subject: [PATCH 16/43] Don't set STILL_FURTHER_SPECIALIZABLE for regions/bound variables --- src/librustc_middle/ty/flags.rs | 2 -- src/librustc_middle/ty/sty.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index bee42be8a5388..d13be4f428534 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -93,7 +93,6 @@ impl FlagComputation { &ty::Bound(debruijn, _) => { self.add_binder(debruijn); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } &ty::Placeholder(..) => { @@ -216,7 +215,6 @@ impl FlagComputation { } ty::ConstKind::Bound(debruijn, _) => { self.add_binder(debruijn); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Param(_) => { self.add_flags(TypeFlags::HAS_CT_PARAM); diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index b0addcb2bb683..1d680c3563675 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -1589,19 +1589,16 @@ impl RegionKind { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PARAM; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::ReFree { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; From db4826dd6ca48663a0b4c5ab0681258999017c7d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Jun 2020 16:50:34 +0100 Subject: [PATCH 17/43] Move bounds on associated types to the type Given `trait X { type U; }` the bound `::U` now lives on the type, rather than the trait. This is feature gated on `feature(generic_associated_types)` for now until more testing can be done. The also enabled type-generic associated types since we no longer need "implies bounds". --- src/librustc_infer/infer/outlives/verify.rs | 21 ++- src/librustc_infer/traits/mod.rs | 2 - src/librustc_middle/query/mod.rs | 10 ++ src/librustc_ty/ty.rs | 57 ++++++-- src/librustc_typeck/check/compare_method.rs | 42 ++---- src/librustc_typeck/collect.rs | 129 +++++++----------- .../feature-gate-generic_associated_types.rs | 2 - ...ature-gate-generic_associated_types.stderr | 30 +--- .../collections-project-default.rs | 72 ++++++++++ .../collections-project-default.stderr | 15 ++ .../generic-associated-types/collections.rs | 33 ++--- .../collections.stderr | 19 --- .../construct_with_other_type.rs | 3 +- .../construct_with_other_type.stderr | 18 --- .../gat-dont-ice-on-absent-feature-2.rs | 1 - .../gat-dont-ice-on-absent-feature-2.stderr | 12 +- .../generic-associated-types-where.rs | 6 +- .../generic-associated-types-where.stderr | 30 ++-- .../issue-47206-where-clause.rs | 2 +- .../issue-47206-where-clause.stderr | 12 +- .../issue-62326-parameter-out-of-range.rs | 7 +- .../issue-62326-parameter-out-of-range.stderr | 10 -- .../generic-associated-types/issue-67424.rs | 1 - .../issue-67424.stderr | 10 +- .../issue-68641-check-gat-bounds.stderr | 4 +- .../issue-68642-broken-llvm-ir.stderr | 4 +- .../issue-68643-broken-mir.stderr | 4 +- .../issue-68644-codegen-selection.stderr | 4 +- .../issue-68645-codegen-fulfillment.stderr | 4 +- .../issue-68656-unsized-values.stderr | 4 +- .../ui/generic-associated-types/iterable.rs | 20 ++- .../generic-associated-types/iterable.stderr | 59 -------- .../missing-bounds.fixed | 5 +- .../missing-bounds.rs | 5 +- .../missing-bounds.stderr | 30 +--- .../parameter_number_and_kind.rs | 6 +- .../parameter_number_and_kind.stderr | 40 +----- .../pointer_family.rs | 3 +- .../pointer_family.stderr | 10 -- .../ui/generic-associated-types/shadowing.rs | 2 - .../generic-associated-types/shadowing.stderr | 20 +-- .../unsatisfied-outlives-bound.rs | 22 +++ .../unsatisfied-outlives-bound.stderr | 23 ++++ src/test/ui/issues/issue-38091.stderr | 10 +- .../deafult-associated-type-bound-1.stderr | 4 +- .../deafult-associated-type-bound-2.stderr | 4 +- ...afult-generic-associated-type-bound.stderr | 6 +- 47 files changed, 342 insertions(+), 495 deletions(-) create mode 100644 src/test/ui/generic-associated-types/collections-project-default.rs create mode 100644 src/test/ui/generic-associated-types/collections-project-default.stderr delete mode 100644 src/test/ui/generic-associated-types/collections.stderr delete mode 100644 src/test/ui/generic-associated-types/construct_with_other_type.stderr delete mode 100644 src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr delete mode 100644 src/test/ui/generic-associated-types/iterable.stderr delete mode 100644 src/test/ui/generic-associated-types/pointer_family.stderr create mode 100644 src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs create mode 100644 src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 82d32b008088d..383979f864075 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -1,9 +1,8 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; -use crate::traits; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -311,18 +310,14 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn region_bounds_declared_on_associated_item( &self, assoc_item_def_id: DefId, - ) -> impl Iterator> + 'cx + Captures<'tcx> { + ) -> impl Iterator> { let tcx = self.tcx; - let assoc_item = tcx.associated_item(assoc_item_def_id); - let trait_def_id = assoc_item.container.assert_trait(); - let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p); - let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id); - let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); - self.collect_outlives_from_predicate_list( - move |ty| ty == identity_proj, - traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate), - ) - .map(|b| b.1) + let predicates = tcx.projection_predicates(assoc_item_def_id); + predicates + .into_iter() + .filter_map(|p| p.to_opt_type_outlives()) + .filter_map(|p| p.no_bound_vars()) + .map(|b| b.1) } /// Searches through a predicate list for a predicate `T: 'a`. diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index a15ac819be966..43b6d8da03a79 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -25,8 +25,6 @@ pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheStorage, Reveal, }; -crate use self::util::elaborate_predicates; - pub use rustc_middle::traits::*; /// An `Obligation` represents some trait reference (e.g., `int: Eq`) for diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index c88718a2761c0..ca51d5b949c06 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -136,6 +136,16 @@ rustc_queries! { /// Returns the list of predicates that can be used for /// `SelectionCandidate::ProjectionCandidate` and /// `ProjectionTyCandidate::TraitDef`. + /// Specifically this is the bounds (equivalent to) those + /// written on the trait's type definition, or those + /// after the `impl` keyword + /// + /// type X: Bound + 'lt + /// ^^^^^^^^^^^ + /// impl Debug + Display + /// ^^^^^^^^^^^^^^^ + /// + /// `key` is the `DefId` of the associated type or opaque type. query projection_predicates(key: DefId) -> &'tcx ty::List> { desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } } diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index dd35202616366..595992d01dd2d 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -371,34 +371,45 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { /// (`type X: Trait`) to be used as candidates. We also allow the same bounds /// when desugared as bounds on the trait `where Self::X: Trait`. /// -/// Note that this filtering is done with the trait's identity substs to +/// Note that this filtering is done with the items identity substs to /// simplify checking that these bounds are met in impls. This means that /// a bound such as `for<'b> >::U: Clone` can't be used, as in /// `hr-associated-type-bound-1.rs`. fn associated_type_projection_predicates( tcx: TyCtxt<'_>, - def_id: DefId, + assoc_item_def_id: DefId, ) -> &'_ ty::List> { - let trait_id = tcx.associated_item(def_id).container.id(); - let trait_substs = InternalSubsts::identity_for_item(tcx, trait_id); - - let generic_trait_bounds = tcx.predicates_of(trait_id); - let trait_bounds = generic_trait_bounds.instantiate_identity(tcx); - let trait_predicates = util::elaborate_predicates(tcx, trait_bounds.predicates.into_iter()); + let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id); + // We include predicates from the trait as well to handle + // `where Self::X: Trait`. + let item_bounds = generic_trait_bounds.instantiate_identity(tcx); + let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter()); + + let assoc_item_ty = ty::ProjectionTy { + item_def_id: assoc_item_def_id, + substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id), + }; - let predicates = trait_predicates.filter_map(|obligation| { + let predicates = item_predicates.filter_map(|obligation| { let pred = obligation.predicate; match pred.kind() { ty::PredicateKind::Trait(tr, _) => { if let ty::Projection(p) = tr.skip_binder().self_ty().kind { - if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + if p == assoc_item_ty { return Some(pred); } } } ty::PredicateKind::Projection(proj) => { if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind { - if p.item_def_id == def_id && p.substs.starts_with(trait_substs) { + if p == assoc_item_ty { + return Some(pred); + } + } + } + ty::PredicateKind::TypeOutlives(outlives) => { + if let ty::Projection(p) = outlives.skip_binder().0.kind { + if p == assoc_item_ty { return Some(pred); } } @@ -409,7 +420,11 @@ fn associated_type_projection_predicates( }); let result = tcx.mk_predicates(predicates); - debug!("associated_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + debug!( + "associated_type_projection_predicates({}) = {:?}", + tcx.def_path_str(assoc_item_def_id), + result + ); result } @@ -422,9 +437,9 @@ fn opaque_type_projection_predicates( ) -> &'_ ty::List> { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let generics_bounds = tcx.predicates_of(def_id); - let bounds = generics_bounds.instantiate_identity(tcx); - let predicates = util::elaborate_predicates(tcx, bounds.predicates.into_iter()); + let bounds = tcx.predicates_of(def_id); + let predicates = + util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred)); let filtered_predicates = predicates.filter_map(|obligation| { let pred = obligation.predicate; @@ -445,6 +460,18 @@ fn opaque_type_projection_predicates( } } } + ty::PredicateKind::TypeOutlives(outlives) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } else { + // These can come from elaborating other predicates + return None; + } + } + // These can come from elaborating other predicates + ty::PredicateKind::RegionOutlives(_) => return None, _ => {} } tcx.sess.delay_span_bug( diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 98c341f4bed41..3a292993e3985 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1189,8 +1189,8 @@ fn compare_projection_bounds<'tcx>( impl_ty_span: Span, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorReported> { - let is_gat = !tcx.generics_of(impl_ty.def_id).params.is_empty(); - if impl_ty.defaultness.is_final() && !is_gat { + let have_gats = tcx.features().generic_associated_types; + if impl_ty.defaultness.is_final() && !have_gats { // For "final", non-generic associate type implementations, we // don't need this as described above. return Ok(()); @@ -1198,7 +1198,9 @@ fn compare_projection_bounds<'tcx>( let param_env = tcx.param_env(impl_ty.def_id); - let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.container.id()); + let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); + let rebased_substs = + impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); let impl_ty_value = tcx.type_of(impl_ty.def_id); // Map the predicate from the trait to the corresponding one for the impl. @@ -1211,32 +1213,9 @@ fn compare_projection_bounds<'tcx>( // function would translate and partially normalize // `[>::Y<'a>, A]` to `[&'a u32, &'x u32]`. let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { - let normalized_self = if !is_gat { - // projection_predicates only includes projections where the - // substs of the trait ref are exactly the trait's identity - // substs, so we can simply return the value from the impl. - impl_ty_value - } else { - let predicate_self_ty = predicate_substs.type_at(0); - let impl_ty_substs = if let ty::Projection(p) = predicate_self_ty.kind { - assert!( - p.item_def_id == trait_ty.def_id, - "projection_predicates returned predicate for the wrong type: {}", - predicate_self_ty, - ); - p.substs.rebase_onto(tcx, impl_trait_ref.def_id, impl_substs) - } else { - bug!( - "projection_predicates returned predicate for the wrong type `{}`", - predicate_self_ty, - ); - }; - impl_ty_value.subst(tcx, impl_ty_substs) - }; - tcx.mk_substs( - iter::once(normalized_self.into()) - .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, impl_trait_ref.substs))), + iter::once(impl_ty_value.into()) + .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))), ) }; @@ -1275,10 +1254,15 @@ fn compare_projection_bounds<'tcx>( substs: projection_substs, item_def_id: projection.projection_ty.item_def_id, }, - ty: projection.ty.subst(tcx, impl_trait_ref.substs), + ty: projection.ty.subst(tcx, rebased_substs), } }) .to_predicate(tcx), + ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives + .map_bound(|outlives| { + ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs)) + }) + .to_predicate(tcx), _ => bug!("unexepected projection predicate kind: `{:?}`", predicate), }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 91266eeb9bab0..054165f2b0977 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -35,7 +35,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; @@ -1692,6 +1692,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut is_trait = None; let mut is_default_impl_trait = None; + let mut is_trait_associated_type = None; let icx = ItemCtxt::new(tcx, def_id); let constness = icx.default_constness_for_trait_bounds(); @@ -1701,7 +1702,12 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut predicates = UniquePredicates::new(); let ast_generics = match node { - Node::TraitItem(item) => &item.generics, + Node::TraitItem(item) => { + if let hir::TraitItemKind::Type(bounds, _) = item.kind { + is_trait_associated_type = Some((bounds, item.span)); + } + &item.generics + } Node::ImplItem(item) => &item.generics, @@ -1925,10 +1931,21 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } - // Add predicates from associated type bounds. - if let Some((self_trait_ref, trait_items)) = is_trait { + // Add predicates from associated type bounds (`type X: Bound`) + if tcx.features().generic_associated_types { + // New behavior: bounds declared on associate type are predicates of that + // associated type. Not the default because it needs more testing. + if let Some((bounds, span)) = is_trait_associated_type { + let projection_ty = + tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id)); + + predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span)) + } + } else if let Some((self_trait_ref, trait_items)) = is_trait { + // Current behavior: bounds declared on associate type are predicates + // of its parent trait. predicates.extend(trait_items.iter().flat_map(|trait_item_ref| { - associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) + trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) })) } @@ -1958,7 +1975,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } -fn associated_item_predicates( +fn trait_associated_item_predicates( tcx: TyCtxt<'tcx>, def_id: DefId, self_trait_ref: ty::TraitRef<'tcx>, @@ -1971,92 +1988,40 @@ fn associated_item_predicates( _ => return Vec::new(), }; - let is_gat = !tcx.generics_of(item_def_id).params.is_empty(); - - let mut had_error = false; - - let mut unimplemented_error = |arg_kind: &str| { - if !had_error { - tcx.sess - .struct_span_err( - trait_item.span, - &format!("{}-generic associated types are not yet implemented", arg_kind), - ) - .note( - "for more information, see issue #44265 \ - for more information", - ) - .emit(); - had_error = true; - } - }; - - let mk_bound_param = |param: &ty::GenericParamDef, _: &_| { - match param.kind { - ty::GenericParamDefKind::Lifetime => tcx - .mk_region(ty::RegionKind::ReLateBound( - ty::INNERMOST, - ty::BoundRegion::BrNamed(param.def_id, param.name), - )) - .into(), - // FIXME(generic_associated_types): Use bound types and constants - // once they are handled by the trait system. - ty::GenericParamDefKind::Type { .. } => { - unimplemented_error("type"); - tcx.ty_error().into() - } - ty::GenericParamDefKind::Const => { - unimplemented_error("const"); - tcx.const_error(tcx.type_of(param.def_id)).into() - } - } - }; + if !tcx.generics_of(item_def_id).params.is_empty() { + // For GATs the substs provided to the mk_projection call below are + // wrong. We should emit a feature gate error if we get here so skip + // this type. + tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate"); + return Vec::new(); + } - let bound_substs = if is_gat { - // Given: - // - // trait X<'a, B, const C: usize> { - // type T<'d, E, const F: usize>: Default; - // } - // - // We need to create predicates on the trait: - // - // for<'d, E, const F: usize> - // >::T<'d, E, const F: usize>: Sized + Default - // - // We substitute escaping bound parameters for the generic - // arguments to the associated type which are then bound by - // the `Binder` around the the predicate. - // - // FIXME(generic_associated_types): Currently only lifetimes are handled. - self_trait_ref.substs.extend_to(tcx, item_def_id.to_def_id(), mk_bound_param) - } else { - self_trait_ref.substs - }; + let assoc_ty = tcx.mk_projection( + tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), + self_trait_ref.substs, + ); - let assoc_ty = - tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), bound_substs); + associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span) +} +fn associated_item_bounds( + tcx: TyCtxt<'tcx>, + def_id: DefId, + bounds: &'tcx [hir::GenericBound<'tcx>], + projection_ty: Ty<'tcx>, + span: Span, +) -> Vec<(ty::Predicate<'tcx>, Span)> { let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, def_id), - assoc_ty, + projection_ty, bounds, SizedByDefault::Yes, - trait_item.span, + span, ); - let predicates = bounds.predicates(tcx, assoc_ty); + let predicates = bounds.predicates(tcx, projection_ty); - if is_gat { - // We use shifts to get the regions that we're substituting to - // be bound by the binders in the `Predicate`s rather that - // escaping. - let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1); - let substituted = shifted_in.subst(tcx, bound_substs); - ty::fold::shift_out_vars(tcx, &substituted, 1) - } else { - predicates - } + predicates } /// Converts a specific `GenericBound` from the AST into a set of diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs index 7ff348aca7cc1..17548d7b9e88c 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs @@ -3,11 +3,9 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; //~^ ERROR generic associated types are unstable - //~| ERROR type-generic associated types are not yet implemented type Pointer2: Deref where T: Clone, U: Clone; //~^ ERROR generic associated types are unstable //~| ERROR where clauses on associated types are unstable - //~| ERROR type-generic associated types are not yet implemented } struct Foo; diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr index a0e06cb2b6795..8499b1ab70f5d 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr @@ -8,7 +8,7 @@ LL | type Pointer: Deref; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:7:5 + --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | type Pointer2: Deref where T: Clone, U: Clone; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:7:5 + --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Pointer2: Deref where T: Clone, U: Clone; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:16:5 + --> $DIR/feature-gate-generic_associated_types.rs:14:5 | LL | type Pointer = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type Pointer = Box; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:18:5 + --> $DIR/feature-gate-generic_associated_types.rs:16:5 | LL | type Pointer2 = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | type Pointer2 = Box; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:23:5 + --> $DIR/feature-gate-generic_associated_types.rs:21:5 | LL | type Assoc where Self: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | type Assoc where Self: Sized; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:28:5 + --> $DIR/feature-gate-generic_associated_types.rs:26:5 | LL | type Assoc where Self: Sized = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,22 +61,6 @@ LL | type Assoc where Self: Sized = Foo; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/feature-gate-generic_associated_types.rs:4:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/feature-gate-generic_associated_types.rs:7:5 - | -LL | type Pointer2: Deref where T: Clone, U: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs new file mode 100644 index 0000000000000..5fbae02573c62 --- /dev/null +++ b/src/test/ui/generic-associated-types/collections-project-default.rs @@ -0,0 +1,72 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] + +// A Collection trait and collection families. Based on +// http://smallcultfollowing.com/babysteps/blog/2016/11/03/ +// associated-type-constructors-part-2-family-traits/ + +// check that we don't normalize with trait defaults. + +trait Collection { + type Iter<'iter>: Iterator where T: 'iter; + type Family: CollectionFamily; + // Test associated type defaults with parameters + type Sibling: Collection = + <>::Family as CollectionFamily>::Member; + + fn empty() -> Self; + + fn add(&mut self, value: T); + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; +} + +trait CollectionFamily { + type Member: Collection; +} + +struct VecFamily; + +impl CollectionFamily for VecFamily { + type Member = Vec; +} + +impl Collection for Vec { + type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>; + type Family = VecFamily; + + fn empty() -> Self { + Vec::new() + } + + fn add(&mut self, value: T) { + self.push(value) + } + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { + self.iter() + } +} + +fn floatify_sibling(ints: &C) -> >::Sibling +where + C: Collection, +{ + let mut res = ::Member::::empty(); + for &v in ints.iterate() { + res.add(v as f32); + } + res + //~^ ERROR mismatched types +} + +fn use_floatify() { + let a = vec![1i32, 2, 3]; + let c = floatify_sibling(&a); + assert_eq!(Some(&1.0), c.iterate().next()); +} + +fn main() { + use_floatify(); +} diff --git a/src/test/ui/generic-associated-types/collections-project-default.stderr b/src/test/ui/generic-associated-types/collections-project-default.stderr new file mode 100644 index 0000000000000..ca02b2603ba64 --- /dev/null +++ b/src/test/ui/generic-associated-types/collections-project-default.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/collections-project-default.rs:60:5 + | +LL | fn floatify_sibling(ints: &C) -> >::Sibling + | ------------------------------------ expected `>::Sibling` because of return type +... +LL | res + | ^^^ expected Collection::Sibling, found CollectionFamily::Member + | + = note: expected associated type `>::Sibling` + found associated type `<>::Family as CollectionFamily>::Member` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs index 6f018f0401863..1b5b9c181fb61 100644 --- a/src/test/ui/generic-associated-types/collections.rs +++ b/src/test/ui/generic-associated-types/collections.rs @@ -6,13 +6,14 @@ // http://smallcultfollowing.com/babysteps/blog/2016/11/03/ // associated-type-constructors-part-2-family-traits/ +// run-pass + trait Collection { - type Iter<'iter>: Iterator; + type Iter<'iter>: Iterator where T: 'iter; type Family: CollectionFamily; // Test associated type defaults with parameters type Sibling: Collection = <>::Family as CollectionFamily>::Member; - //~^^ ERROR type-generic associated types are not yet implemented fn empty() -> Self; @@ -23,7 +24,6 @@ trait Collection { trait CollectionFamily { type Member: Collection; - //~^ ERROR type-generic associated types are not yet implemented } struct VecFamily; @@ -33,7 +33,7 @@ impl CollectionFamily for VecFamily { } impl Collection for Vec { - type Iter<'iter> = std::slice::Iter<'iter, T>; + type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>; type Family = VecFamily; fn empty() -> Self { @@ -53,18 +53,7 @@ fn floatify(ints: &C) -> <>::Family as CollectionFamily> where C: Collection, { - let mut res = C::Family::Member::::empty(); - for &v in ints.iterate() { - res.add(v as f32); - } - res -} - -fn floatify_sibling(ints: &C) -> >::Sibling -where - C: Collection, -{ - let mut res = C::Family::Member::::empty(); + let mut res = ::Member::::empty(); for &v in ints.iterate() { res.add(v as f32); } @@ -72,11 +61,11 @@ where } fn use_floatify() { - let a = vec![1i32, 2, 3]; - let b = floatify(a); - println!("{}", b.iterate().next()); - let c = floatify_sibling(a); - println!("{}", c.iterate().next()); + let a = vec![1, 2, 3]; + let b = floatify(&a); + assert_eq!(Some(&1.0), b.iterate().next()); } -fn main() {} +fn main() { + use_floatify(); +} diff --git a/src/test/ui/generic-associated-types/collections.stderr b/src/test/ui/generic-associated-types/collections.stderr deleted file mode 100644 index fb06d5e49a391..0000000000000 --- a/src/test/ui/generic-associated-types/collections.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: type-generic associated types are not yet implemented - --> $DIR/collections.rs:13:5 - | -LL | / type Sibling: Collection = -LL | | <>::Family as CollectionFamily>::Member; - | |_________________________________________________________________________^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/collections.rs:25:5 - | -LL | type Member: Collection; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.rs b/src/test/ui/generic-associated-types/construct_with_other_type.rs index 2198b99db25c1..ff9d61658f4eb 100644 --- a/src/test/ui/generic-associated-types/construct_with_other_type.rs +++ b/src/test/ui/generic-associated-types/construct_with_other_type.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#30472) normalize enough to handle this. +// check-pass use std::ops::Deref; @@ -17,7 +17,6 @@ trait Baz { } impl Baz for T where T: Foo { -//~^ ERROR type mismatch resolving type Quux<'a> where T: 'a = T; type Baa<'a> where T: 'a = &'a ::Bar<'a, 'static>; diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.stderr b/src/test/ui/generic-associated-types/construct_with_other_type.stderr deleted file mode 100644 index b9468b3330b44..0000000000000 --- a/src/test/ui/generic-associated-types/construct_with_other_type.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0271]: type mismatch resolving `for<'a> <::Baa<'a> as std::ops::Deref>::Target == <::Quux<'a> as Foo>::Bar<'a, 'static>` - --> $DIR/construct_with_other_type.rs:19:9 - | -LL | impl Baz for T where T: Foo { - | - ^^^ expected type parameter `T`, found associated type - | | - | this type parameter - | - = note: expected associated type `::Bar<'_, 'static>` - found associated type `<::Quux<'_> as Foo>::Bar<'_, 'static>` -help: consider further restricting this bound - | -LL | impl Baz for T where T: Foo + Baz { - | ^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs index f88df6a608aa3..c1d68812e9356 100644 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs +++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs @@ -6,7 +6,6 @@ struct Foo; trait MyTrait { type Item; //~^ ERROR generic associated types are unstable [E0658] - //~| ERROR type-generic associated types are not yet implemented } impl MyTrait for Foo { diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr index f3da27775adcf..34f536dbe8f64 100644 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr +++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr @@ -8,7 +8,7 @@ LL | type Item; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:13:5 + --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5 | LL | type Item = T; | ^^^^^^^^^^^^^^^^^ @@ -16,14 +16,6 @@ LL | type Item = T; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5 - | -LL | type Item; - | ^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs index 589024e162166..1a94796535c14 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs @@ -9,11 +9,8 @@ use std::fmt::{Display, Debug}; trait Foo { type Assoc where Self: Sized; type Assoc2 where T: Display; - //~^ ERROR type-generic associated types are not yet implemented type Assoc3; - //~^ ERROR type-generic associated types are not yet implemented - type WithDefault<'a, T: Debug + 'a> = dyn Iterator; - //~^ ERROR type-generic associated types are not yet implemented + type WithDefault<'a, T: Debug + 'a>: ?Sized = dyn Iterator; type NoGenerics; } @@ -23,6 +20,7 @@ impl Foo for Bar { type Assoc = usize; type Assoc2 = Vec; type Assoc3 where T: Iterator = Vec; + //~^ impl has stricter requirements than trait type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator; type NoGenerics = ::std::cell::Cell; } diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index fb29b377a16e3..4d02f2c46a6d0 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -1,26 +1,12 @@ -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:11:5 - | -LL | type Assoc2 where T: Display; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:13:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/generic-associated-types-where.rs:22:5 | LL | type Assoc3; - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:15:5 - | -LL | type WithDefault<'a, T: Debug + 'a> = dyn Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information + | --------------- definition of `Assoc3` from trait +... +LL | type Assoc3 where T: Iterator = Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` -error: aborting due to 3 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs index 53e350aacf88e..de2b978460f7f 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs @@ -5,13 +5,13 @@ trait Foo { type Assoc3; - //~^ type-generic associated types are not yet implemented } struct Bar; impl Foo for Bar { type Assoc3 where T: Iterator = Vec; + //~^ ERROR impl has stricter requirements than trait } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index c9c1a4753b0dd..bc5c40ff029f9 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -1,10 +1,12 @@ -error: type-generic associated types are not yet implemented - --> $DIR/issue-47206-where-clause.rs:7:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-47206-where-clause.rs:13:5 | LL | type Assoc3; - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information + | --------------- definition of `Assoc3` from trait +... +LL | type Assoc3 where T: Iterator = Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` error: aborting due to previous error +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs index 1a79dbf2279a0..404be59a36d92 100644 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs +++ b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs @@ -1,11 +1,14 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(generic-associated-types) Investigate why this doesn't compile. +// check-pass trait Iterator { type Item<'a>: 'a; - //~^ ERROR the requirement `for<'a> ::Item<'a>: 'a` is not satisfied +} + +impl Iterator for () { + type Item<'a> = &'a (); } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr deleted file mode 100644 index 4b06baa09ffbf..0000000000000 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0280]: the requirement `for<'a> ::Item<'a>: 'a` is not satisfied - --> $DIR/issue-62326-parameter-out-of-range.rs:7:20 - | -LL | trait Iterator { - | -------- required by a bound in this -LL | type Item<'a>: 'a; - | ^^ required by this bound in `Iterator` - -error: aborting due to previous error - diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs index 9b616b8abc2ee..fa35a3e8b04d1 100644 --- a/src/test/ui/generic-associated-types/issue-67424.rs +++ b/src/test/ui/generic-associated-types/issue-67424.rs @@ -7,7 +7,6 @@ trait Trait1 { trait Trait2 { type Type1: Trait1; //~^ ERROR: generic associated types are unstable - //~| ERROR: type-generic associated types are not yet implemented } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr index 8b08c71759bb9..bbb7d56f5928e 100644 --- a/src/test/ui/generic-associated-types/issue-67424.stderr +++ b/src/test/ui/generic-associated-types/issue-67424.stderr @@ -7,14 +7,6 @@ LL | type Type1: Trait1; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/issue-67424.rs:8:5 - | -LL | type Type1: Trait1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr index eeff7c340ac96..834bc3b7878f2 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-68641-check-gat-bounds.rs:15:5 | -LL | trait UnsafeCopy { - | ---------------- required by `UnsafeCopy` +LL | type Item<'a>: Copy; + | -------------------- required by `UnsafeCopy::Item` ... LL | type Item<'a> = T; | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index b3d4b8d465180..89cc5dfd06018 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index 6e23fe02de8cd..efd3287853f03 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68643-broken-mir.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index 234f5c8a0cc02..5da924a512f00 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68644-codegen-selection.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index ac2d5063fbb5d..12d84ab6a369b 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 | -LL | trait Fun { - | --------- required by `Fun` +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` ... LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr index e4eb7991f7637..e1ceeac3196a8 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -10,8 +10,8 @@ LL | #![feature(generic_associated_types)] error[E0271]: type mismatch resolving `::Target == T` --> $DIR/issue-68656-unsized-values.rs:16:5 | -LL | trait UnsafeCopy { - | ------------------------- required by `UnsafeCopy` +LL | type Item<'a>: std::ops::Deref; + | ------------------------------------------- required by `UnsafeCopy::Item` ... LL | impl UnsafeCopy for T { | - this type parameter diff --git a/src/test/ui/generic-associated-types/iterable.rs b/src/test/ui/generic-associated-types/iterable.rs index 105ab4a8adc38..600a69006c1ea 100644 --- a/src/test/ui/generic-associated-types/iterable.rs +++ b/src/test/ui/generic-associated-types/iterable.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#30472) normalize enough to handle this. +// run-pass trait Iterable { type Item<'a> where Self: 'a; @@ -13,39 +13,35 @@ trait Iterable { // Impl for struct type impl Iterable for Vec { type Item<'a> where T: 'a = as Iterator>::Item; - //~^ ERROR type mismatch resolving type Iter<'a> where T: 'a = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR type mismatch resolving - self.iter() + self[..].iter() } } // Impl for a primitive type impl Iterable for [T] { type Item<'a> where T: 'a = as Iterator>::Item; - //~^ ERROR type mismatch resolving type Iter<'a> where T: 'a = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR type mismatch resolving self.iter() } } -fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { +fn make_iter<'a, I: Iterable + ?Sized>(it: &'a I) -> I::Iter<'a> { it.iter() } -fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { +fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option> { it.iter().next() } fn main() { let v = vec![1, 2, 3]; - assert_eq!(v, make_iter(&v).copied().collect()); - assert_eq!(v, make_iter(&*v).copied().collect()); - assert_eq!(1, get_first(&v)); - assert_eq!(1, get_first(&*v)); + assert_eq!(v, make_iter(&v).copied().collect::>()); + assert_eq!(v, make_iter(&*v).copied().collect::>()); + assert_eq!(Some(&1), get_first(&v)); + assert_eq!(Some(&1), get_first(&*v)); } diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr deleted file mode 100644 index 6e75462122513..0000000000000 --- a/src/test/ui/generic-associated-types/iterable.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error[E0271]: type mismatch resolving `for<'a> < as Iterable>::Iter<'a> as std::iter::Iterator>::Item == as Iterable>::Item<'a>` - --> $DIR/iterable.rs:15:33 - | -LL | type Item<'a> where T: 'a = as Iterator>::Item; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type - | - = note: expected reference `&T` - found associated type ` as Iterable>::Item<'_>` - = help: consider constraining the associated type ` as Iterable>::Item<'_>` to `&_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` - --> $DIR/iterable.rs:27:33 - | -LL | type Item<'a> where T: 'a = as Iterator>::Item; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type - | - = note: expected reference `&T` - found associated type `<[T] as Iterable>::Item<'_>` - = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> < as Iterable>::Iter<'a> as std::iter::Iterator>::Item == as Iterable>::Item<'a>` - --> $DIR/iterable.rs:19:30 - | -LL | trait Iterable { - | -------- required by a bound in this -LL | type Item<'a> where Self: 'a; -LL | type Iter<'a>: Iterator> where Self: 'a; - | --------------------- required by this bound in `Iterable` -... -LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { - | ^^^^^^^^^^^^^^ expected associated type, found reference - | - = note: expected associated type ` as Iterable>::Item<'_>` - found reference `&T` - = help: consider constraining the associated type ` as Iterable>::Item<'_>` to `&_` or calling a method that returns ` as Iterable>::Item<'_>` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` - --> $DIR/iterable.rs:31:30 - | -LL | trait Iterable { - | -------- required by a bound in this -LL | type Item<'a> where Self: 'a; -LL | type Iter<'a>: Iterator> where Self: 'a; - | --------------------- required by this bound in `Iterable` -... -LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { - | ^^^^^^^^^^^^^^ expected associated type, found reference - | - = note: expected associated type `<[T] as Iterable>::Item<'_>` - found reference `&T` - = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 364d2388741b0..3ba7d043d0759 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -34,12 +34,11 @@ impl> Add for D { struct E(B); -impl Add for E where B: Add, B: std::ops::Add { - //~^ ERROR equality constraints are not yet supported in `where` clauses +impl Add for E where B: Add { type Output = Self; fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) //~ ERROR mismatched types + Self(self.0 + rhs.0) } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs index ffafff5e9f586..962d2db9476bd 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.rs +++ b/src/test/ui/generic-associated-types/missing-bounds.rs @@ -34,12 +34,11 @@ impl Add for D { struct E(B); -impl Add for E where ::Output = B { - //~^ ERROR equality constraints are not yet supported in `where` clauses +impl Add for E where B: Add { type Output = Self; fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) //~ ERROR mismatched types + Self(self.0 + rhs.0) } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 50536fdaca96e..630ceac093ef2 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -1,15 +1,3 @@ -error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:37:33 - | -LL | impl Add for E where ::Output = B { - | ^^^^^^^^^^^^^^^^^^^^^^ not supported - | - = note: see issue #20041 for more information -help: if `Output` is an associated type you're trying to set, use the associated type binding syntax - | -LL | impl Add for E where B: Add { - | ^^^^^^^^^^^^^^^^^^ - error[E0308]: mismatched types --> $DIR/missing-bounds.rs:11:11 | @@ -55,23 +43,7 @@ help: consider restricting type parameter `B` LL | impl> Add for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:42:14 - | -LL | impl Add for E where ::Output = B { - | - this type parameter -... -LL | Self(self.0 + rhs.0) - | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type - | - = note: expected type parameter `B` - found associated type `::Output` -help: consider further restricting type parameter `B` - | -LL | impl Add for E where ::Output = B, B: std::ops::Add { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs index 0edc5c48c01af..f4d09fc1539da 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs @@ -7,18 +7,14 @@ trait Foo { type B<'a, 'b>; type C; type D; - //~^ ERROR type-generic associated types are not yet implemented type E<'a, T>; - //~^ ERROR type-generic associated types are not yet implemented // Test parameters in default values type FOk = Self::E<'static, T>; - //~^ ERROR type-generic associated types are not yet implemented type FErr1 = Self::E<'static, 'static>; //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 type FErr2 = Self::E<'static, T, u32>; - //~^ ERROR type-generic associated types are not yet implemented - //~| ERROR wrong number of type arguments: expected 1, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 } fn main() {} diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr index 028ab72f48812..ed090e302cefa 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr @@ -1,53 +1,21 @@ -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:9:5 - | -LL | type D; - | ^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:11:5 - | -LL | type E<'a, T>; - | ^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:14:5 - | -LL | type FOk = Self::E<'static, T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:19:5 - | -LL | type FErr2 = Self::E<'static, T, u32>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - error[E0107]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/parameter_number_and_kind.rs:16:35 + --> $DIR/parameter_number_and_kind.rs:13:35 | LL | type FErr1 = Self::E<'static, 'static>; | ^^^^^^^ unexpected lifetime argument error[E0107]: wrong number of type arguments: expected 1, found 0 - --> $DIR/parameter_number_and_kind.rs:16:18 + --> $DIR/parameter_number_and_kind.rs:13:18 | LL | type FErr1 = Self::E<'static, 'static>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument error[E0107]: wrong number of type arguments: expected 1, found 2 - --> $DIR/parameter_number_and_kind.rs:19:41 + --> $DIR/parameter_number_and_kind.rs:16:41 | LL | type FErr2 = Self::E<'static, T, u32>; | ^^^ unexpected type argument -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/pointer_family.rs b/src/test/ui/generic-associated-types/pointer_family.rs index 1668759b4e39c..b322b752a1567 100644 --- a/src/test/ui/generic-associated-types/pointer_family.rs +++ b/src/test/ui/generic-associated-types/pointer_family.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#44265): allow type-generic associated types. +// check-pass use std::rc::Rc; use std::sync::Arc; @@ -9,7 +9,6 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; - //~^ ERROR type-generic associated types are not yet implemented fn new(value: T) -> Self::Pointer; } diff --git a/src/test/ui/generic-associated-types/pointer_family.stderr b/src/test/ui/generic-associated-types/pointer_family.stderr deleted file mode 100644 index 83fe992fcb571..0000000000000 --- a/src/test/ui/generic-associated-types/pointer_family.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: type-generic associated types are not yet implemented - --> $DIR/pointer_family.rs:11:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to previous error - diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs index 5c308948bd3f8..44528ca1da36e 100644 --- a/src/test/ui/generic-associated-types/shadowing.rs +++ b/src/test/ui/generic-associated-types/shadowing.rs @@ -18,12 +18,10 @@ impl<'a> NoShadow<'a> for &'a u32 { trait ShadowT { type Bar; //~^ ERROR the name `T` is already used - //~| ERROR type-generic associated types are not yet implemented } trait NoShadowT { type Bar; // OK - //~^ ERROR type-generic associated types are not yet implemented } impl NoShadowT for Option { diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 2d9a0d6fceb2d..d51c29080a0c9 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -7,7 +7,7 @@ LL | type Bar; | ^ already used error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowing.rs:30:14 + --> $DIR/shadowing.rs:28:14 | LL | impl NoShadowT for Option { | - first use of `T` @@ -30,23 +30,7 @@ LL | impl<'a> NoShadow<'a> for &'a u32 { LL | type Bar<'a> = i32; | ^^ lifetime 'a already in scope -error: type-generic associated types are not yet implemented - --> $DIR/shadowing.rs:19:5 - | -LL | type Bar; - | ^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/shadowing.rs:25:5 - | -LL | type Bar; // OK - | ^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0403, E0496. For more information about an error, try `rustc --explain E0403`. diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs new file mode 100644 index 0000000000000..7510c58d57489 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs @@ -0,0 +1,22 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +trait ATy { + type Item<'a>: 'a; +} + +impl<'b> ATy for &'b () { + type Item<'a> = &'b (); + //~^ ERROR does not fulfill the required lifetime +} + +trait StaticTy { + type Item<'a>: 'static; +} + +impl StaticTy for () { + type Item<'a> = &'a (); + //~^ ERROR does not fulfill the required lifetime +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr new file mode 100644 index 0000000000000..5d612284a2187 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr @@ -0,0 +1,23 @@ +error[E0477]: the type `&'b ()` does not fulfill the required lifetime + --> $DIR/unsatisfied-outlives-bound.rs:9:5 + | +LL | type Item<'a> = &'b (); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type must outlive the lifetime `'a` as defined on the associated item at 9:15 + --> $DIR/unsatisfied-outlives-bound.rs:9:15 + | +LL | type Item<'a> = &'b (); + | ^^ + +error[E0477]: the type `&'a ()` does not fulfill the required lifetime + --> $DIR/unsatisfied-outlives-bound.rs:18:5 + | +LL | type Item<'a> = &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type must satisfy the static lifetime + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr index 4d3369c5b6486..81beec8026314 100644 --- a/src/test/ui/issues/issue-38091.stderr +++ b/src/test/ui/issues/issue-38091.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-38091.rs:2:12 + --> $DIR/issue-38091.rs:1:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -8,14 +8,14 @@ LL | #![feature(specialization)] = note: see issue #31844 for more information error[E0277]: the trait bound `(): Valid` is not satisfied - --> $DIR/issue-38091.rs:8:5 + --> $DIR/issue-38091.rs:9:5 | -LL | trait Iterate<'a> { - | ----------------- required by `Iterate` +LL | type Ty: Valid; + | --------------- required by `Iterate::Ty` ... LL | default type Ty = (); | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()` -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr index 8b3d6a913a7a0..90ad5d4c1559b 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -10,8 +10,8 @@ LL | #![feature(specialization)] error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied --> $DIR/deafult-associated-type-bound-1.rs:18:5 | -LL | trait X { - | ------- required by `X` +LL | type U: Clone; + | -------------- required by `X::U` ... LL | default type U = str; | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index 4d21f47051fab..ea40f846e3665 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -10,8 +10,8 @@ LL | #![feature(specialization)] error[E0277]: can't compare `&'static B` with `B` --> $DIR/deafult-associated-type-bound-2.rs:16:5 | -LL | trait X { - | ---------- required by `X` +LL | type U: PartialEq; + | --------------------- required by `X::U` ... LL | default type U = &'static B; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index 1aac9e70d87d8..7f3c49e753fd7 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -18,14 +18,14 @@ LL | #![feature(generic_associated_types)] error[E0277]: can't compare `T` with `T` --> $DIR/deafult-generic-associated-type-bound.rs:19:5 | -LL | trait X { - | ------- required by `X` +LL | type U<'a>: PartialEq<&'a Self>; + | -------------------------------- required by `X::U` ... LL | default type U<'a> = &'a T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` | = help: the trait `std::cmp::PartialEq` is not implemented for `T` - = note: required because of the requirements on the impl of `for<'a> std::cmp::PartialEq` for `&'a T` + = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` help: consider further restricting this bound | LL | impl X for T { From 5e8c9f4fae106d0ba836a0268ab4e44c19d63f2a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 13 Jun 2020 17:31:48 +0100 Subject: [PATCH 18/43] Explain what the substs we're creating are --- src/librustc_typeck/check/compare_method.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 3a292993e3985..4c39b2a3b612d 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1198,6 +1198,15 @@ fn compare_projection_bounds<'tcx>( let param_env = tcx.param_env(impl_ty.def_id); + // Given + // + // impl Foo for (A, B) { + // type Bar =... + // } + // + // - `impl_substs` would be `[A, B, C]` + // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from + // the *trait* with the generic associated type parameters. let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); let rebased_substs = impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); From 3ff5879f8d50da4807c639a17df5884bcaa8b319 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 30 May 2020 14:55:38 -0400 Subject: [PATCH 19/43] core/time: Add Duration methods for zero This patch adds two methods to `Duration`. The first, `Duration::zero`, provides a `const` constructor for getting an zero-length duration. This is also what `Default` provides (this was clarified in the docs), though `default` is not `const`. The second, `Duration::is_zero`, returns true if a `Duration` spans no time (i.e., because its components are all zero). Previously, the way to do this was either to compare both `as_secs` and `subsec_nanos` to 0, to compare against `Duration::new(0, 0)`, or to use the `u128` method `as_nanos`, none of which were particularly elegant. --- src/libcore/time.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e2ceaf80c0cda..cf88ff2e10fb7 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -31,7 +31,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// the number of nanoseconds. /// /// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other -/// [`ops`] traits. +/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`. /// /// [`Add`]: ../../std/ops/trait.Add.html /// [`Sub`]: ../../std/ops/trait.Sub.html @@ -223,6 +223,47 @@ impl Duration { } } + /// Creates a new `Duration` that spans no time. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::zero(); + /// assert!(duration.is_zero()); + /// + /// const IMMEDIATELY: Duration = Duration::zero(); + /// assert!(IMMEDIATELY.is_zero()); + /// ``` + #[unstable(feature = "duration_zero", issue = "none")] + #[inline] + pub const fn zero() -> Duration { + Duration { secs: 0, nanos: 0 } + } + + /// Returns true if this `Duration` spans no time. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// assert!(Duration::zero().is_zero()); + /// assert!(Duration::new(0, 0).is_zero()); + /// assert!(Duration::from_nanos(0).is_zero()); + /// assert!(Duration::from_secs(0).is_zero()); + /// + /// assert!(!Duration::new(1, 1).is_zero()); + /// assert!(!Duration::from_nanos(1).is_zero()); + /// assert!(!Duration::from_secs(1).is_zero()); + /// ``` + #[unstable(feature = "duration_zero", issue = "none")] + #[inline] + pub const fn is_zero(&self) -> bool { + self.secs == 0 && self.nanos == 0 + } + /// Returns the number of _whole_ seconds contained by this `Duration`. /// /// The returned value does not include the fractional (nanosecond) part of the From ad7fd6265e62b2170612544caea3b8454ebb3fed Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 30 May 2020 15:20:09 -0400 Subject: [PATCH 20/43] Doctests need feature --- src/libcore/time.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index cf88ff2e10fb7..d94f2378058e7 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -228,6 +228,7 @@ impl Duration { /// # Examples /// /// ``` + /// #![feature(duration_zero)] /// use std::time::Duration; /// /// let duration = Duration::zero(); @@ -247,6 +248,7 @@ impl Duration { /// # Examples /// /// ``` + /// #![feature(duration_zero)] /// use std::time::Duration; /// /// assert!(Duration::zero().is_zero()); From 386114bfd3c8240154a00b00296da9f105bd97ce Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 20 Jun 2020 10:55:39 -0400 Subject: [PATCH 21/43] Revise according to review --- src/libcore/time.rs | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index d94f2378058e7..3b6dafeee2540 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -138,6 +138,24 @@ impl Duration { Duration { secs, nanos } } + /// Creates a new `Duration` that spans no time. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_zero)] + /// use std::time::Duration; + /// + /// let duration = Duration::zero(); + /// assert!(duration.is_zero()); + /// assert_eq!(duration.as_nanos(), 0); + /// ``` + #[unstable(feature = "duration_zero", issue = "73544")] + #[inline] + pub const fn zero() -> Duration { + Duration { secs: 0, nanos: 0 } + } + /// Creates a new `Duration` from the specified number of whole seconds. /// /// # Examples @@ -223,26 +241,6 @@ impl Duration { } } - /// Creates a new `Duration` that spans no time. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_zero)] - /// use std::time::Duration; - /// - /// let duration = Duration::zero(); - /// assert!(duration.is_zero()); - /// - /// const IMMEDIATELY: Duration = Duration::zero(); - /// assert!(IMMEDIATELY.is_zero()); - /// ``` - #[unstable(feature = "duration_zero", issue = "none")] - #[inline] - pub const fn zero() -> Duration { - Duration { secs: 0, nanos: 0 } - } - /// Returns true if this `Duration` spans no time. /// /// # Examples @@ -260,7 +258,7 @@ impl Duration { /// assert!(!Duration::from_nanos(1).is_zero()); /// assert!(!Duration::from_secs(1).is_zero()); /// ``` - #[unstable(feature = "duration_zero", issue = "none")] + #[unstable(feature = "duration_zero", issue = "73544")] #[inline] pub const fn is_zero(&self) -> bool { self.secs == 0 && self.nanos == 0 From c883fa45d39a5ef7316e2b6637885ec222b609d5 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 10 Jun 2020 17:47:13 -0700 Subject: [PATCH 22/43] Allow multiple `asm!` options --- src/librustc_builtin_macros/asm.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 2988567960464..e98431a269591 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -16,7 +16,7 @@ struct AsmArgs { named_args: FxHashMap, reg_args: FxHashSet, options: ast::InlineAsmOptions, - options_span: Option, + options_spans: Option>, } fn parse_args<'a>( @@ -59,7 +59,7 @@ fn parse_args<'a>( named_args: FxHashMap::default(), reg_args: FxHashSet::default(), options: ast::InlineAsmOptions::empty(), - options_span: None, + options_spans: None, }; let mut allow_templates = true; @@ -174,9 +174,9 @@ fn parse_args<'a>( // Validate the order of named, positional & explicit register operands and options. We do // this at the end once we have the full span of the argument available. - if let Some(options_span) = args.options_span { + if let Some(ref options_spans) = args.options_spans { ecx.struct_span_err(span, "arguments are not allowed after options") - .span_label(options_span, "previous options") + .span_labels(options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); } @@ -227,21 +227,21 @@ fn parse_args<'a>( if args.options.contains(ast::InlineAsmOptions::NOMEM) && args.options.contains(ast::InlineAsmOptions::READONLY) { - let span = args.options_span.unwrap(); - ecx.struct_span_err(span, "the `nomem` and `readonly` options are mutually exclusive") + let spans = args.options_spans.clone().unwrap(); + ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive") .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && args.options.contains(ast::InlineAsmOptions::NORETURN) { - let span = args.options_span.unwrap(); - ecx.struct_span_err(span, "the `pure` and `noreturn` options are mutually exclusive") + let spans = args.options_spans.clone().unwrap(); + ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive") .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { - let span = args.options_span.unwrap(); + let span = args.options_spans.clone().unwrap(); ecx.struct_span_err( span, "the `pure` option must be combined with either `nomem` or `readonly`", @@ -267,7 +267,7 @@ fn parse_args<'a>( } if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { ecx.struct_span_err( - args.options_span.unwrap(), + args.options_spans.clone().unwrap(), "asm with `pure` option must have at least one output", ) .emit(); @@ -314,13 +314,10 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn } let new_span = span_start.to(p.prev_token.span); - if let Some(options_span) = args.options_span { - p.struct_span_err(new_span, "asm options cannot be specified multiple times") - .span_label(options_span, "previously here") - .span_label(new_span, "duplicate options") - .emit(); + if let Some(options_spans) = &mut args.options_spans { + options_spans.push(new_span); } else { - args.options_span = Some(new_span); + args.options_spans = Some(vec![new_span]); } Ok(()) From e61411673c8e47c504ff36cbc3479c0dd8939309 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 10 Jun 2020 18:21:22 -0700 Subject: [PATCH 23/43] Update tests --- src/test/ui/asm/parse-error.rs | 5 ---- src/test/ui/asm/parse-error.stderr | 48 ++++++++---------------------- 2 files changed, 12 insertions(+), 41 deletions(-) diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs index fbf399d8b075c..538a3fde8fdeb 100644 --- a/src/test/ui/asm/parse-error.rs +++ b/src/test/ui/asm/parse-error.rs @@ -34,11 +34,6 @@ fn main() { //~^ ERROR expected one of asm!("", options(nomem, foo)); //~^ ERROR expected one of - asm!("", options(), options()); - //~^ ERROR asm options cannot be specified multiple times - asm!("", options(), options(), options()); - //~^ ERROR asm options cannot be specified multiple times - //~^^ ERROR asm options cannot be specified multiple times asm!("{}", options(), const foo); //~^ ERROR arguments are not allowed after options asm!("{a}", a = const foo, a = const bar); diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index ba7e8f7a03cca..dfbfc0abe3472 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -82,32 +82,8 @@ error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `prese LL | asm!("", options(nomem, foo)); | ^^^ expected one of 8 possible tokens -error: asm options cannot be specified multiple times - --> $DIR/parse-error.rs:37:29 - | -LL | asm!("", options(), options()); - | --------- ^^^^^^^^^ duplicate options - | | - | previously here - -error: asm options cannot be specified multiple times - --> $DIR/parse-error.rs:39:29 - | -LL | asm!("", options(), options(), options()); - | --------- ^^^^^^^^^ duplicate options - | | - | previously here - -error: asm options cannot be specified multiple times - --> $DIR/parse-error.rs:39:40 - | -LL | asm!("", options(), options(), options()); - | --------- ^^^^^^^^^ duplicate options - | | - | previously here - error: arguments are not allowed after options - --> $DIR/parse-error.rs:42:31 + --> $DIR/parse-error.rs:37:31 | LL | asm!("{}", options(), const foo); | --------- ^^^^^^^^^ argument @@ -115,7 +91,7 @@ LL | asm!("{}", options(), const foo); | previous options error: duplicate argument named `a` - --> $DIR/parse-error.rs:44:36 + --> $DIR/parse-error.rs:39:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -123,7 +99,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:44:36 + --> $DIR/parse-error.rs:39:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used @@ -131,13 +107,13 @@ LL | asm!("{a}", a = const foo, a = const bar); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:47:18 + --> $DIR/parse-error.rs:42:18 | LL | asm!("", a = in("eax") foo); | ^^^^^^^^^^^^^^^^^ error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:49:36 + --> $DIR/parse-error.rs:44:36 | LL | asm!("{a}", in("eax") foo, a = const bar); | ------------- ^^^^^^^^^^^^^ named argument @@ -145,7 +121,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | explicit register argument error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:51:36 + --> $DIR/parse-error.rs:46:36 | LL | asm!("{a}", in("eax") foo, a = const bar); | ------------- ^^^^^^^^^^^^^ named argument @@ -153,7 +129,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | explicit register argument error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:53:36 + --> $DIR/parse-error.rs:48:36 | LL | asm!("{1}", in("eax") foo, const bar); | ------------- ^^^^^^^^^ positional argument @@ -161,19 +137,19 @@ LL | asm!("{1}", in("eax") foo, const bar); | explicit register argument error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:55:29 + --> $DIR/parse-error.rs:50:29 | LL | asm!("", options(), ""); | ^^ expected one of 8 possible tokens error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:57:33 + --> $DIR/parse-error.rs:52:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); | ^^^^ expected one of 8 possible tokens error: asm template must be a string literal - --> $DIR/parse-error.rs:59:14 + --> $DIR/parse-error.rs:54:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -181,12 +157,12 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:61:21 + --> $DIR/parse-error.rs:56:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 28 previous errors +error: aborting due to 25 previous errors From 1d2acdf8ec1959424be2728fa868e91b3eaeedc6 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 12 Jun 2020 11:31:41 -0700 Subject: [PATCH 24/43] Use `Vec` instead of `Option>` --- src/librustc_builtin_macros/asm.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index e98431a269591..8f6b8903d6676 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -16,7 +16,7 @@ struct AsmArgs { named_args: FxHashMap, reg_args: FxHashSet, options: ast::InlineAsmOptions, - options_spans: Option>, + options_spans: Vec, } fn parse_args<'a>( @@ -59,7 +59,7 @@ fn parse_args<'a>( named_args: FxHashMap::default(), reg_args: FxHashSet::default(), options: ast::InlineAsmOptions::empty(), - options_spans: None, + options_spans: vec![], }; let mut allow_templates = true; @@ -174,9 +174,9 @@ fn parse_args<'a>( // Validate the order of named, positional & explicit register operands and options. We do // this at the end once we have the full span of the argument available. - if let Some(ref options_spans) = args.options_spans { + if args.options_spans.len() > 0 { ecx.struct_span_err(span, "arguments are not allowed after options") - .span_labels(options_spans.clone(), "previous options") + .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); } @@ -227,21 +227,21 @@ fn parse_args<'a>( if args.options.contains(ast::InlineAsmOptions::NOMEM) && args.options.contains(ast::InlineAsmOptions::READONLY) { - let spans = args.options_spans.clone().unwrap(); + let spans = args.options_spans.clone(); ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive") .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && args.options.contains(ast::InlineAsmOptions::NORETURN) { - let spans = args.options_spans.clone().unwrap(); + let spans = args.options_spans.clone(); ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive") .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { - let span = args.options_spans.clone().unwrap(); + let span = args.options_spans.clone(); ecx.struct_span_err( span, "the `pure` option must be combined with either `nomem` or `readonly`", @@ -267,7 +267,7 @@ fn parse_args<'a>( } if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { ecx.struct_span_err( - args.options_spans.clone().unwrap(), + args.options_spans.clone(), "asm with `pure` option must have at least one output", ) .emit(); @@ -314,11 +314,7 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn } let new_span = span_start.to(p.prev_token.span); - if let Some(options_spans) = &mut args.options_spans { - options_spans.push(new_span); - } else { - args.options_spans = Some(vec![new_span]); - } + args.options_spans.push(new_span); Ok(()) } From 27cc7c7d9fb8a25cce9ab73ece034a9282406ce3 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 12 Jun 2020 11:39:52 -0700 Subject: [PATCH 25/43] Clean up --- src/librustc_builtin_macros/asm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 8f6b8903d6676..2be45daef989c 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -174,7 +174,7 @@ fn parse_args<'a>( // Validate the order of named, positional & explicit register operands and options. We do // this at the end once we have the full span of the argument available. - if args.options_spans.len() > 0 { + if !args.options_spans.is_empty() { ecx.struct_span_err(span, "arguments are not allowed after options") .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") @@ -241,9 +241,9 @@ fn parse_args<'a>( if args.options.contains(ast::InlineAsmOptions::PURE) && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { - let span = args.options_spans.clone(); + let spans = args.options_spans.clone(); ecx.struct_span_err( - span, + spans, "the `pure` option must be combined with either `nomem` or `readonly`", ) .emit(); From 820bba1c467aa5aa54d6db2869b15c643e5c350c Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 12 Jun 2020 12:12:36 -0700 Subject: [PATCH 26/43] Add codegen test for multiple `asm!` options --- src/test/codegen/asm-multiple-options.rs | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/codegen/asm-multiple-options.rs diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs new file mode 100644 index 0000000000000..c702742bf1a63 --- /dev/null +++ b/src/test/codegen/asm-multiple-options.rs @@ -0,0 +1,53 @@ +// compile-flags: -O +// only-x86_64 + +#![crate_type = "rlib"] +#![feature(asm)] + +// CHECK-LABEL: @pure +// CHECK-NOT: asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn pure(x: i32) { + let y: i32; + asm!("", out("ax") y, in("bx") x, options(pure), options(nomem)); +} + +pub static mut VAR: i32 = 0; +pub static mut DUMMY_OUTPUT: i32 = 0; + +// CHECK-LABEL: @readonly +// CHECK: call i32 asm +// CHECK: ret i32 1 +#[no_mangle] +pub unsafe fn readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); + VAR +} + +// CHECK-LABEL: @nomem +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @not_nomem +// CHECK: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn not_nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); + VAR = 2; + VAR +} From 2be403ce3e0bc21b36a6ef783476095d2e921fca Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 13 Jun 2020 17:06:35 -0700 Subject: [PATCH 27/43] Warn on duplicate `asm!` options --- src/librustc_builtin_macros/asm.rs | 65 ++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 2be45daef989c..b5641fdf2ab0f 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -19,6 +19,12 @@ struct AsmArgs { options_spans: Vec, } +impl AsmArgs { + fn option_is_set(&self, option: ast::InlineAsmOptions) -> bool { + (self.options & option) == option + } +} + fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, @@ -283,6 +289,23 @@ fn parse_args<'a>( Ok(args) } +fn warn_duplicate_option<'a>(p: &mut Parser<'a>, span: Span) { + let mut warn = if let Ok(snippet) = p.sess.source_map().span_to_snippet(span) { + p.sess + .span_diagnostic + .struct_span_warn(span, &format!("the `{}` option was already provided", snippet)) + } else { + p.sess.span_diagnostic.struct_span_warn(span, "this option was already provided") + }; + warn.span_suggestion( + span, + "remove this option", + String::new(), + Applicability::MachineApplicable, + ); + warn.emit(); +} + fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> { let span_start = p.prev_token.span; @@ -290,20 +313,48 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) { if p.eat(&token::Ident(sym::pure, false)) { - args.options |= ast::InlineAsmOptions::PURE; + if !args.option_is_set(ast::InlineAsmOptions::PURE) { + args.options |= ast::InlineAsmOptions::PURE; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } else if p.eat(&token::Ident(sym::nomem, false)) { - args.options |= ast::InlineAsmOptions::NOMEM; + if !args.option_is_set(ast::InlineAsmOptions::NOMEM) { + args.options |= ast::InlineAsmOptions::NOMEM; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } else if p.eat(&token::Ident(sym::readonly, false)) { - args.options |= ast::InlineAsmOptions::READONLY; + if !args.option_is_set(ast::InlineAsmOptions::READONLY) { + args.options |= ast::InlineAsmOptions::READONLY; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } else if p.eat(&token::Ident(sym::preserves_flags, false)) { - args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS; + if !args.option_is_set(ast::InlineAsmOptions::PRESERVES_FLAGS) { + args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } else if p.eat(&token::Ident(sym::noreturn, false)) { - args.options |= ast::InlineAsmOptions::NORETURN; + if !args.option_is_set(ast::InlineAsmOptions::NORETURN) { + args.options |= ast::InlineAsmOptions::NORETURN; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } else if p.eat(&token::Ident(sym::nostack, false)) { - args.options |= ast::InlineAsmOptions::NOSTACK; + if !args.option_is_set(ast::InlineAsmOptions::NOSTACK) { + args.options |= ast::InlineAsmOptions::NOSTACK; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } else { p.expect(&token::Ident(sym::att_syntax, false))?; - args.options |= ast::InlineAsmOptions::ATT_SYNTAX; + if !args.option_is_set(ast::InlineAsmOptions::ATT_SYNTAX) { + args.options |= ast::InlineAsmOptions::ATT_SYNTAX; + } else { + warn_duplicate_option(p, p.prev_token.span); + } } // Allow trailing commas From 7aaadb69e45134277e6091ec1ce173c0787cf896 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 13 Jun 2020 17:59:13 -0700 Subject: [PATCH 28/43] Add UI test for duplicate `asm!` options warning --- src/test/ui/asm/duplicate-options.rs | 19 ++++++++++++ src/test/ui/asm/duplicate-options.stderr | 38 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/test/ui/asm/duplicate-options.rs create mode 100644 src/test/ui/asm/duplicate-options.stderr diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs new file mode 100644 index 0000000000000..9c447451511b4 --- /dev/null +++ b/src/test/ui/asm/duplicate-options.rs @@ -0,0 +1,19 @@ +// only-x86_64 +// build-pass + +#![feature(asm)] + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ WARNING the `nomem` option was already provided + asm!("", options(att_syntax, att_syntax)); + //~^ WARNING the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options(nostack)); + //~^ WARNING the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ WARNING the `nostack` option was already provided + //~| WARNING the `nostack` option was already provided + //~| WARNING the `nostack` option was already provided + } +} diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr new file mode 100644 index 0000000000000..113aca8da900f --- /dev/null +++ b/src/test/ui/asm/duplicate-options.stderr @@ -0,0 +1,38 @@ +warning: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:8:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ help: remove this option + +warning: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:10:38 + | +LL | asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ help: remove this option + +warning: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:12:56 + | +LL | asm!("", options(nostack, att_syntax), options(nostack)); + | ^^^^^^^ help: remove this option + +warning: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ help: remove this option + +warning: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ help: remove this option + +warning: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ help: remove this option + +warning: 6 warnings emitted + From b94b7e7f1bf4e05d28ec7fca305c1d49f242c3dd Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 14 Jun 2020 13:38:09 -0700 Subject: [PATCH 29/43] Make warning an error; use help instead of suggestion; clean up code For some reason, the help message is now in a separate message, which adds a lot of noise. I would like to try to get it back to one message. --- src/librustc_builtin_macros/asm.rs | 67 +++++++--------------- src/test/ui/asm/duplicate-options.rs | 19 ++++--- src/test/ui/asm/duplicate-options.stderr | 72 ++++++++++++++++++------ 3 files changed, 87 insertions(+), 71 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index b5641fdf2ab0f..922a06bae93e4 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -289,21 +289,24 @@ fn parse_args<'a>( Ok(args) } -fn warn_duplicate_option<'a>(p: &mut Parser<'a>, span: Span) { - let mut warn = if let Ok(snippet) = p.sess.source_map().span_to_snippet(span) { +fn err_duplicate_option<'a>(p: &mut Parser<'a>, span: Span) { + let mut err = if let Ok(snippet) = p.sess.source_map().span_to_snippet(span) { p.sess .span_diagnostic - .struct_span_warn(span, &format!("the `{}` option was already provided", snippet)) + .struct_span_err(span, &format!("the `{}` option was already provided", snippet)) } else { - p.sess.span_diagnostic.struct_span_warn(span, "this option was already provided") + p.sess.span_diagnostic.struct_span_err(span, "this option was already provided") }; - warn.span_suggestion( - span, - "remove this option", - String::new(), - Applicability::MachineApplicable, - ); - warn.emit(); + err.span_help(span, "remove this option"); + err.emit(); +} + +fn try_set_option<'a>(p: &mut Parser<'a>, args: &mut AsmArgs, option: ast::InlineAsmOptions) { + if !args.option_is_set(option) { + args.options |= option; + } else { + err_duplicate_option(p, p.prev_token.span); + } } fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> { @@ -313,48 +316,20 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) { if p.eat(&token::Ident(sym::pure, false)) { - if !args.option_is_set(ast::InlineAsmOptions::PURE) { - args.options |= ast::InlineAsmOptions::PURE; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::PURE); } else if p.eat(&token::Ident(sym::nomem, false)) { - if !args.option_is_set(ast::InlineAsmOptions::NOMEM) { - args.options |= ast::InlineAsmOptions::NOMEM; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::NOMEM); } else if p.eat(&token::Ident(sym::readonly, false)) { - if !args.option_is_set(ast::InlineAsmOptions::READONLY) { - args.options |= ast::InlineAsmOptions::READONLY; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::READONLY); } else if p.eat(&token::Ident(sym::preserves_flags, false)) { - if !args.option_is_set(ast::InlineAsmOptions::PRESERVES_FLAGS) { - args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::PRESERVES_FLAGS); } else if p.eat(&token::Ident(sym::noreturn, false)) { - if !args.option_is_set(ast::InlineAsmOptions::NORETURN) { - args.options |= ast::InlineAsmOptions::NORETURN; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::NORETURN); } else if p.eat(&token::Ident(sym::nostack, false)) { - if !args.option_is_set(ast::InlineAsmOptions::NOSTACK) { - args.options |= ast::InlineAsmOptions::NOSTACK; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::NOSTACK); } else { p.expect(&token::Ident(sym::att_syntax, false))?; - if !args.option_is_set(ast::InlineAsmOptions::ATT_SYNTAX) { - args.options |= ast::InlineAsmOptions::ATT_SYNTAX; - } else { - warn_duplicate_option(p, p.prev_token.span); - } + try_set_option(p, args, ast::InlineAsmOptions::ATT_SYNTAX); } // Allow trailing commas diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs index 9c447451511b4..e412932fa7ebe 100644 --- a/src/test/ui/asm/duplicate-options.rs +++ b/src/test/ui/asm/duplicate-options.rs @@ -1,19 +1,24 @@ // only-x86_64 -// build-pass #![feature(asm)] fn main() { unsafe { asm!("", options(nomem, nomem)); - //~^ WARNING the `nomem` option was already provided + //~^ ERROR the `nomem` option was already provided + //~| HELP remove this option asm!("", options(att_syntax, att_syntax)); - //~^ WARNING the `att_syntax` option was already provided + //~^ ERROR the `att_syntax` option was already provided + //~| HELP remove this option asm!("", options(nostack, att_syntax), options(nostack)); - //~^ WARNING the `nostack` option was already provided + //~^ ERROR the `nostack` option was already provided + //~| HELP remove this option asm!("", options(nostack, nostack), options(nostack), options(nostack)); - //~^ WARNING the `nostack` option was already provided - //~| WARNING the `nostack` option was already provided - //~| WARNING the `nostack` option was already provided + //~^ ERROR the `nostack` option was already provided + //~| HELP remove this option + //~| ERROR the `nostack` option was already provided + //~| HELP remove this option + //~| ERROR the `nostack` option was already provided + //~| HELP remove this option } } diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr index 113aca8da900f..accfdef474bb9 100644 --- a/src/test/ui/asm/duplicate-options.stderr +++ b/src/test/ui/asm/duplicate-options.stderr @@ -1,38 +1,74 @@ -warning: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:8:33 +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:7:33 | LL | asm!("", options(nomem, nomem)); - | ^^^^^ help: remove this option + | ^^^^^ + | +help: remove this option + --> $DIR/duplicate-options.rs:7:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ -warning: the `att_syntax` option was already provided +error: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:10:38 + | +LL | asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ + | +help: remove this option --> $DIR/duplicate-options.rs:10:38 | LL | asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ help: remove this option + | ^^^^^^^^^^ -warning: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:12:56 +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:13:56 + | +LL | asm!("", options(nostack, att_syntax), options(nostack)); + | ^^^^^^^ + | +help: remove this option + --> $DIR/duplicate-options.rs:13:56 | LL | asm!("", options(nostack, att_syntax), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ -warning: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:14:35 +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:16:35 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ + | +help: remove this option + --> $DIR/duplicate-options.rs:16:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ -warning: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:14:53 +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:16:53 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ + | +help: remove this option + --> $DIR/duplicate-options.rs:16:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ -warning: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:14:71 +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:16:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ + | +help: remove this option + --> $DIR/duplicate-options.rs:16:71 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ -warning: 6 warnings emitted +error: aborting due to 6 previous errors From ac54265b137b307e5a369b9e8c78126784b8427b Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 15 Jun 2020 11:57:49 -0700 Subject: [PATCH 30/43] Use `span_label` --- src/librustc_builtin_macros/asm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 922a06bae93e4..474c54c998d99 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -297,7 +297,7 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, span: Span) { } else { p.sess.span_diagnostic.struct_span_err(span, "this option was already provided") }; - err.span_help(span, "remove this option"); + err.span_label(span, "remove this option"); err.emit(); } From 7c5b66f3287c95df7e1aaca1d2a0576eed69f7dd Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 15 Jun 2020 12:11:49 -0700 Subject: [PATCH 31/43] Update duplicate options test --- src/test/ui/asm/duplicate-options.rs | 6 --- src/test/ui/asm/duplicate-options.stderr | 58 +++++------------------- 2 files changed, 11 insertions(+), 53 deletions(-) diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs index e412932fa7ebe..1df7f55f81248 100644 --- a/src/test/ui/asm/duplicate-options.rs +++ b/src/test/ui/asm/duplicate-options.rs @@ -6,19 +6,13 @@ fn main() { unsafe { asm!("", options(nomem, nomem)); //~^ ERROR the `nomem` option was already provided - //~| HELP remove this option asm!("", options(att_syntax, att_syntax)); //~^ ERROR the `att_syntax` option was already provided - //~| HELP remove this option asm!("", options(nostack, att_syntax), options(nostack)); //~^ ERROR the `nostack` option was already provided - //~| HELP remove this option asm!("", options(nostack, nostack), options(nostack), options(nostack)); //~^ ERROR the `nostack` option was already provided - //~| HELP remove this option //~| ERROR the `nostack` option was already provided - //~| HELP remove this option //~| ERROR the `nostack` option was already provided - //~| HELP remove this option } } diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr index accfdef474bb9..6339ae9db8105 100644 --- a/src/test/ui/asm/duplicate-options.stderr +++ b/src/test/ui/asm/duplicate-options.stderr @@ -2,73 +2,37 @@ error: the `nomem` option was already provided --> $DIR/duplicate-options.rs:7:33 | LL | asm!("", options(nomem, nomem)); - | ^^^^^ - | -help: remove this option - --> $DIR/duplicate-options.rs:7:33 - | -LL | asm!("", options(nomem, nomem)); - | ^^^^^ + | ^^^^^ remove this option error: the `att_syntax` option was already provided - --> $DIR/duplicate-options.rs:10:38 - | -LL | asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ - | -help: remove this option - --> $DIR/duplicate-options.rs:10:38 + --> $DIR/duplicate-options.rs:9:38 | LL | asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ + | ^^^^^^^^^^ remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:13:56 - | -LL | asm!("", options(nostack, att_syntax), options(nostack)); - | ^^^^^^^ - | -help: remove this option - --> $DIR/duplicate-options.rs:13:56 + --> $DIR/duplicate-options.rs:11:56 | LL | asm!("", options(nostack, att_syntax), options(nostack)); - | ^^^^^^^ + | ^^^^^^^ remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:16:35 + --> $DIR/duplicate-options.rs:13:35 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ - | -help: remove this option - --> $DIR/duplicate-options.rs:16:35 - | -LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ + | ^^^^^^^ remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:16:53 + --> $DIR/duplicate-options.rs:13:53 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ - | -help: remove this option - --> $DIR/duplicate-options.rs:16:53 - | -LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ + | ^^^^^^^ remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:16:71 - | -LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ - | -help: remove this option - --> $DIR/duplicate-options.rs:16:71 + --> $DIR/duplicate-options.rs:13:71 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ + | ^^^^^^^ remove this option error: aborting due to 6 previous errors From c7da50d23f4fdcd2952a336d661373050730657b Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 15 Jun 2020 12:07:46 -0700 Subject: [PATCH 32/43] Get option name from symbol instead of snippet --- src/librustc_builtin_macros/asm.rs | 36 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 474c54c998d99..5bb2408580290 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -289,23 +289,25 @@ fn parse_args<'a>( Ok(args) } -fn err_duplicate_option<'a>(p: &mut Parser<'a>, span: Span) { - let mut err = if let Ok(snippet) = p.sess.source_map().span_to_snippet(span) { - p.sess - .span_diagnostic - .struct_span_err(span, &format!("the `{}` option was already provided", snippet)) - } else { - p.sess.span_diagnostic.struct_span_err(span, "this option was already provided") - }; +fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { + let mut err = p + .sess + .span_diagnostic + .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); err.span_label(span, "remove this option"); err.emit(); } -fn try_set_option<'a>(p: &mut Parser<'a>, args: &mut AsmArgs, option: ast::InlineAsmOptions) { +fn try_set_option<'a>( + p: &mut Parser<'a>, + args: &mut AsmArgs, + symbol: Symbol, + option: ast::InlineAsmOptions, +) { if !args.option_is_set(option) { args.options |= option; } else { - err_duplicate_option(p, p.prev_token.span); + err_duplicate_option(p, symbol, p.prev_token.span); } } @@ -316,20 +318,20 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) { if p.eat(&token::Ident(sym::pure, false)) { - try_set_option(p, args, ast::InlineAsmOptions::PURE); + try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE); } else if p.eat(&token::Ident(sym::nomem, false)) { - try_set_option(p, args, ast::InlineAsmOptions::NOMEM); + try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM); } else if p.eat(&token::Ident(sym::readonly, false)) { - try_set_option(p, args, ast::InlineAsmOptions::READONLY); + try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY); } else if p.eat(&token::Ident(sym::preserves_flags, false)) { - try_set_option(p, args, ast::InlineAsmOptions::PRESERVES_FLAGS); + try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS); } else if p.eat(&token::Ident(sym::noreturn, false)) { - try_set_option(p, args, ast::InlineAsmOptions::NORETURN); + try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN); } else if p.eat(&token::Ident(sym::nostack, false)) { - try_set_option(p, args, ast::InlineAsmOptions::NOSTACK); + try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK); } else { p.expect(&token::Ident(sym::att_syntax, false))?; - try_set_option(p, args, ast::InlineAsmOptions::ATT_SYNTAX); + try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); } // Allow trailing commas From e8be7971d1217312499c1258a1bb337fcdf3afa6 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 15 Jun 2020 13:30:13 -0700 Subject: [PATCH 33/43] Use bitflags function instead of custom one --- src/librustc_builtin_macros/asm.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 5bb2408580290..db4fae606ad34 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -19,12 +19,6 @@ struct AsmArgs { options_spans: Vec, } -impl AsmArgs { - fn option_is_set(&self, option: ast::InlineAsmOptions) -> bool { - (self.options & option) == option - } -} - fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, @@ -304,7 +298,7 @@ fn try_set_option<'a>( symbol: Symbol, option: ast::InlineAsmOptions, ) { - if !args.option_is_set(option) { + if !args.options.contains(option) { args.options |= option; } else { err_duplicate_option(p, symbol, p.prev_token.span); From b00b1a45982a9f44d3339eab2142dc5f7278f812 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 16 Jun 2020 11:54:12 -0700 Subject: [PATCH 34/43] Use `span_suggestion` instead of `span_label` --- src/librustc_builtin_macros/asm.rs | 2 +- src/test/ui/asm/duplicate-options.stderr | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index db4fae606ad34..675cc904a9f04 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -288,7 +288,7 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { .sess .span_diagnostic .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); - err.span_label(span, "remove this option"); + err.span_suggestion(span, "remove this option", String::new(), Applicability::Unspecified); err.emit(); } diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr index 6339ae9db8105..356e27df19e58 100644 --- a/src/test/ui/asm/duplicate-options.stderr +++ b/src/test/ui/asm/duplicate-options.stderr @@ -2,37 +2,37 @@ error: the `nomem` option was already provided --> $DIR/duplicate-options.rs:7:33 | LL | asm!("", options(nomem, nomem)); - | ^^^^^ remove this option + | ^^^^^ help: remove this option error: the `att_syntax` option was already provided --> $DIR/duplicate-options.rs:9:38 | LL | asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ remove this option + | ^^^^^^^^^^ help: remove this option error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:11:56 | LL | asm!("", options(nostack, att_syntax), options(nostack)); - | ^^^^^^^ remove this option + | ^^^^^^^ help: remove this option error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:13:35 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ remove this option + | ^^^^^^^ help: remove this option error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:13:53 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ remove this option + | ^^^^^^^ help: remove this option error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:13:71 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ remove this option + | ^^^^^^^ help: remove this option error: aborting due to 6 previous errors From f4dfc61e847c5a587aaf09635643034ec900ace8 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 16 Jun 2020 12:03:19 -0700 Subject: [PATCH 35/43] Add more to duplicate options test --- src/test/ui/asm/duplicate-options.rs | 7 +++++++ src/test/ui/asm/duplicate-options.stderr | 20 +++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs index 1df7f55f81248..34371b854f8e2 100644 --- a/src/test/ui/asm/duplicate-options.rs +++ b/src/test/ui/asm/duplicate-options.rs @@ -14,5 +14,12 @@ fn main() { //~^ ERROR the `nostack` option was already provided //~| ERROR the `nostack` option was already provided //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); } } diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr index 356e27df19e58..9aa699c4e76e8 100644 --- a/src/test/ui/asm/duplicate-options.stderr +++ b/src/test/ui/asm/duplicate-options.stderr @@ -34,5 +34,23 @@ error: the `nostack` option was already provided LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ help: remove this option -error: aborting due to 6 previous errors +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:20:33 + | +LL | options(att_syntax, noreturn), + | ^^^^^^^^ help: remove this option + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:21:21 + | +LL | options(nomem, nostack), + | ^^^^^ help: remove this option + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:22:21 + | +LL | options(noreturn), + | ^^^^^^^^ help: remove this option + +error: aborting due to 9 previous errors From 4ba66970d87684fa412a6475bf68ed6042c9e1e9 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 16 Jun 2020 12:32:13 -0700 Subject: [PATCH 36/43] Make suggestion machine-applicable --- src/librustc_builtin_macros/asm.rs | 13 ++++++++++-- src/test/ui/asm/duplicate-options.fixed | 26 ++++++++++++++++++++++++ src/test/ui/asm/duplicate-options.rs | 1 + src/test/ui/asm/duplicate-options.stderr | 20 +++++++++--------- 4 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/asm/duplicate-options.fixed diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 675cc904a9f04..7e5eca29aeada 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -288,7 +288,12 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { .sess .span_diagnostic .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); - err.span_suggestion(span, "remove this option", String::new(), Applicability::Unspecified); + err.span_suggestion( + span, + "remove this option", + String::new(), + Applicability::MachineApplicable, + ); err.emit(); } @@ -301,7 +306,11 @@ fn try_set_option<'a>( if !args.options.contains(option) { args.options |= option; } else { - err_duplicate_option(p, symbol, p.prev_token.span); + let mut span = p.prev_token.span; + if p.look_ahead(0, |t| t == &token::Comma) { + span = span.to(p.token.span); + } + err_duplicate_option(p, symbol, span); } } diff --git a/src/test/ui/asm/duplicate-options.fixed b/src/test/ui/asm/duplicate-options.fixed new file mode 100644 index 0000000000000..f4672a50fd0f4 --- /dev/null +++ b/src/test/ui/asm/duplicate-options.fixed @@ -0,0 +1,26 @@ +// only-x86_64 +// run-rustfix + +#![feature(asm)] + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, )); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs index 34371b854f8e2..80292d7521a9a 100644 --- a/src/test/ui/asm/duplicate-options.rs +++ b/src/test/ui/asm/duplicate-options.rs @@ -1,4 +1,5 @@ // only-x86_64 +// run-rustfix #![feature(asm)] diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr index 9aa699c4e76e8..46a966ddc8606 100644 --- a/src/test/ui/asm/duplicate-options.stderr +++ b/src/test/ui/asm/duplicate-options.stderr @@ -1,53 +1,53 @@ error: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:7:33 + --> $DIR/duplicate-options.rs:8:33 | LL | asm!("", options(nomem, nomem)); | ^^^^^ help: remove this option error: the `att_syntax` option was already provided - --> $DIR/duplicate-options.rs:9:38 + --> $DIR/duplicate-options.rs:10:38 | LL | asm!("", options(att_syntax, att_syntax)); | ^^^^^^^^^^ help: remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:11:56 + --> $DIR/duplicate-options.rs:12:56 | LL | asm!("", options(nostack, att_syntax), options(nostack)); | ^^^^^^^ help: remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:13:35 + --> $DIR/duplicate-options.rs:14:35 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ help: remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:13:53 + --> $DIR/duplicate-options.rs:14:53 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ help: remove this option error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:13:71 + --> $DIR/duplicate-options.rs:14:71 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ help: remove this option error: the `noreturn` option was already provided - --> $DIR/duplicate-options.rs:20:33 + --> $DIR/duplicate-options.rs:21:33 | LL | options(att_syntax, noreturn), | ^^^^^^^^ help: remove this option error: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:21:21 + --> $DIR/duplicate-options.rs:22:21 | LL | options(nomem, nostack), - | ^^^^^ help: remove this option + | ^^^^^^ help: remove this option error: the `noreturn` option was already provided - --> $DIR/duplicate-options.rs:22:21 + --> $DIR/duplicate-options.rs:23:21 | LL | options(noreturn), | ^^^^^^^^ help: remove this option From 8fe6710b4db48e60f49c0d237d324d5490dc4f8e Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 16 Jun 2020 12:43:03 -0700 Subject: [PATCH 37/43] Create a separate, tool-only suggestion for the comma That way the comma isn't highlighted as part of the option in the UI. Weirdly, the comma removal suggestion shows up in the UI. --- src/librustc_builtin_macros/asm.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 7e5eca29aeada..1d59029333db0 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -294,6 +294,14 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { String::new(), Applicability::MachineApplicable, ); + if p.look_ahead(0, |t| t == &token::Comma) { + err.tool_only_span_suggestion( + p.token.span, + "remove this comma", + String::new(), + Applicability::MachineApplicable, + ); + } err.emit(); } @@ -306,11 +314,7 @@ fn try_set_option<'a>( if !args.options.contains(option) { args.options |= option; } else { - let mut span = p.prev_token.span; - if p.look_ahead(0, |t| t == &token::Comma) { - span = span.to(p.token.span); - } - err_duplicate_option(p, symbol, span); + err_duplicate_option(p, symbol, p.prev_token.span); } } From db9d3769b4f26b45b390d350ed3319433cd5e42c Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 16 Jun 2020 18:10:26 -0700 Subject: [PATCH 38/43] Add documentation --- src/librustc_builtin_macros/asm.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 1d59029333db0..9c8e148f83a33 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -283,6 +283,10 @@ fn parse_args<'a>( Ok(args) } +/// Report a duplicate option error. +/// +/// This function must be called immediately after the option token is parsed. +/// Otherwise, the suggestion will be incorrect. fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { let mut err = p .sess @@ -305,6 +309,11 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { err.emit(); } +/// Try to set the provided option in the provided `AsmArgs`. +/// If it is already set, report a duplicate option error. +/// +/// This function must be called immediately after the option token is parsed. +/// Otherwise, the error will not point to the correct spot. fn try_set_option<'a>( p: &mut Parser<'a>, args: &mut AsmArgs, From 58f812bd610c214d5b0ea9493ae362f451378239 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 17 Jun 2020 19:02:57 -0700 Subject: [PATCH 39/43] Use `p.token` instead of `p.look_ahead()` --- src/librustc_builtin_macros/asm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 9c8e148f83a33..119536da05024 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -298,7 +298,7 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { String::new(), Applicability::MachineApplicable, ); - if p.look_ahead(0, |t| t == &token::Comma) { + if p.token.kind == token::Comma { err.tool_only_span_suggestion( p.token.span, "remove this comma", From 8d80cc56794e43f5c6e89550dc6ac64101e278fa Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 19 Jun 2020 20:18:32 -0700 Subject: [PATCH 40/43] Fix duplicate options error The UI isn't glitching anymore. --- src/librustc_builtin_macros/asm.rs | 21 ++++++++++++--------- src/test/ui/asm/duplicate-options.stderr | 18 +++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 119536da05024..6fa04c279d269 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -292,20 +292,23 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { .sess .span_diagnostic .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); - err.span_suggestion( + err.span_label( span, + "this option was already provided", + ); + + // Tool-only output + let mut full_span = span; + if p.token.kind == token::Comma { + full_span = full_span.to(p.token.span); + } + err.tool_only_span_suggestion( + full_span, "remove this option", String::new(), Applicability::MachineApplicable, ); - if p.token.kind == token::Comma { - err.tool_only_span_suggestion( - p.token.span, - "remove this comma", - String::new(), - Applicability::MachineApplicable, - ); - } + err.emit(); } diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr index 46a966ddc8606..cd8d743e031a5 100644 --- a/src/test/ui/asm/duplicate-options.stderr +++ b/src/test/ui/asm/duplicate-options.stderr @@ -2,55 +2,55 @@ error: the `nomem` option was already provided --> $DIR/duplicate-options.rs:8:33 | LL | asm!("", options(nomem, nomem)); - | ^^^^^ help: remove this option + | ^^^^^ this option was already provided error: the `att_syntax` option was already provided --> $DIR/duplicate-options.rs:10:38 | LL | asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ help: remove this option + | ^^^^^^^^^^ this option was already provided error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:12:56 | LL | asm!("", options(nostack, att_syntax), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ this option was already provided error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:14:35 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ this option was already provided error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:14:53 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ this option was already provided error: the `nostack` option was already provided --> $DIR/duplicate-options.rs:14:71 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ help: remove this option + | ^^^^^^^ this option was already provided error: the `noreturn` option was already provided --> $DIR/duplicate-options.rs:21:33 | LL | options(att_syntax, noreturn), - | ^^^^^^^^ help: remove this option + | ^^^^^^^^ this option was already provided error: the `nomem` option was already provided --> $DIR/duplicate-options.rs:22:21 | LL | options(nomem, nostack), - | ^^^^^^ help: remove this option + | ^^^^^ this option was already provided error: the `noreturn` option was already provided --> $DIR/duplicate-options.rs:23:21 | LL | options(noreturn), - | ^^^^^^^^ help: remove this option + | ^^^^^^^^ this option was already provided error: aborting due to 9 previous errors From c31785a4ed13f1a1bab752ea3c1177f7256e4f11 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 19 Jun 2020 20:25:36 -0700 Subject: [PATCH 41/43] Run `./x.py fmt` --- src/librustc_builtin_macros/asm.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 6fa04c279d269..52f86aa7e06b9 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -292,10 +292,7 @@ fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { .sess .span_diagnostic .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); - err.span_label( - span, - "this option was already provided", - ); + err.span_label(span, "this option was already provided"); // Tool-only output let mut full_span = span; From 5a8e915725a2e2eace517ac82fcf5e7e677f245b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 16 Jun 2020 08:52:00 -0700 Subject: [PATCH 42/43] Update bootstrap to rustc 1.45.0-beta.2 (1dc0f6d8e 2020-06-15) --- src/stage0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stage0.txt b/src/stage0.txt index 5e840b9db1994..769ec669bdc8d 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.(x+1).0` for Cargo where they were released on `date`. -date: 2020-06-03 +date: 2020-06-16 rustc: beta cargo: beta From bfb0e8db88d5a9fbb908e88e7588ee9e917cee25 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 20 Jun 2020 12:27:16 -0700 Subject: [PATCH 43/43] Fix broken inner_deref doc tests. --- src/libcore/result.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 2080ae193667e..0c0e6d291bb92 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1155,6 +1155,7 @@ impl Result { /// # Examples /// /// ``` + /// #![feature(inner_deref)] /// let x: Result = Ok("hello".to_string()); /// let y: Result<&str, &u32> = Ok("hello"); /// assert_eq!(x.as_deref(), y); @@ -1189,12 +1190,15 @@ impl Result { /// # Examples /// /// ``` + /// #![feature(inner_deref)] + /// let mut s = "HELLO".to_string(); /// let mut x: Result = Ok("hello".to_string()); - /// let y: Result<&mut str, &mut u32> = Ok("HELLO"); + /// let y: Result<&mut str, &mut u32> = Ok(&mut s); /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); /// + /// let mut i = 42; /// let mut x: Result = Err(42); - /// let y: Result<&mut str, &mut u32> = Err(&42); + /// let y: Result<&mut str, &mut u32> = Err(&mut i); /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); /// ``` pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {