From 25a7d2d540656e0499a43bfd01243250f2a25d7a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 10 Mar 2022 08:47:53 -0600 Subject: [PATCH 01/12] Fix `cargo run tidy` When I implemented rust-only bootstrapping in https://github.com/rust-lang/rust/pull/92260, I neglected to test stage0 tools - it turns out they were broken because they couldn't find the sysroot of the initial bootstrap compiler. This fixes stage0 tools by using `rustc --print sysroot` instead of assuming rustc is already in a sysroot and hard-coding the relative directory. --- src/bootstrap/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2ae63858ff610..91a0e40ca183d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -117,6 +117,7 @@ use std::os::unix::fs::symlink as symlink_file; use std::os::windows::fs::symlink_file; use filetime::FileTime; +use once_cell::sync::OnceCell; use crate::builder::Kind; use crate::config::{LlvmLibunwind, TargetSelection}; @@ -892,7 +893,12 @@ impl Build { /// Returns the sysroot of the snapshot compiler. fn rustc_snapshot_sysroot(&self) -> &Path { - self.initial_rustc.parent().unwrap().parent().unwrap() + static SYSROOT_CACHE: OnceCell = once_cell::sync::OnceCell::new(); + SYSROOT_CACHE.get_or_init(|| { + let mut rustc = Command::new(&self.initial_rustc); + rustc.args(&["--print", "sysroot"]); + output(&mut rustc).trim().into() + }) } /// Runs a command, printing out nice contextual information if it fails. From 38e0ae590caab982a4305da58a0a62385c2dd880 Mon Sep 17 00:00:00 2001 From: Grisha Vartanyan Date: Wed, 23 Mar 2022 22:13:55 +0100 Subject: [PATCH 02/12] Reduce max hash in raw strings from u16 to u8 --- compiler/rustc_lexer/src/lib.rs | 14 +++++++------- compiler/rustc_lexer/src/tests.rs | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 5b8300ab530f9..a41e0374f410a 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -161,15 +161,15 @@ pub enum LiteralKind { /// "b"abc"", "b"abc" ByteStr { terminated: bool }, /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a" - RawStr { n_hashes: u16, err: Option }, + RawStr { n_hashes: u8, err: Option }, /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a" - RawByteStr { n_hashes: u16, err: Option }, + RawByteStr { n_hashes: u8, err: Option }, } /// Error produced validating a raw string. Represents cases like: /// - `r##~"abcde"##`: `InvalidStarter` /// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)` -/// - Too many `#`s (>65535): `TooManyDelimiters` +/// - Too many `#`s (>255): `TooManyDelimiters` // perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum RawStrError { @@ -178,7 +178,7 @@ pub enum RawStrError { /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they /// may have intended to terminate it. NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option }, - /// More than 65535 `#`s exist. + /// More than 255 `#`s exist. TooManyDelimiters { found: usize }, } @@ -698,12 +698,12 @@ impl Cursor<'_> { } /// Eats the double-quoted string and returns `n_hashes` and an error if encountered. - fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u16, Option) { + fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u8, Option) { // Wrap the actual function to handle the error with too many hashes. // This way, it eats the whole raw string. let (n_hashes, err) = self.raw_string_unvalidated(prefix_len); - // Only up to 65535 `#`s are allowed in raw strings - match u16::try_from(n_hashes) { + // Only up to 255 `#`s are allowed in raw strings + match u8::try_from(n_hashes) { Ok(num) => (num, err), // We lie about the number of hashes here :P Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })), diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 548de67449abf..07daee06f0f86 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -2,7 +2,7 @@ use super::*; use expect_test::{expect, Expect}; -fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { +fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option) { let s = &format!("r{}", s); let mut cursor = Cursor::new(s); cursor.bump(); @@ -68,13 +68,13 @@ fn test_unterminated_no_pound() { #[test] fn test_too_many_hashes() { - let max_count = u16::MAX; + let max_count = u8::MAX; let mut hashes: String = "#".repeat(max_count.into()); - // Valid number of hashes (65535 = 2^16 - 1), but invalid string. + // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string. check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' })); - // One more hash sign (65536 = 2^16) becomes too many. + // One more hash sign (256 = 2^8) becomes too many. hashes.push('#'); check_raw_str( &hashes, From b51f20eaf5cc311ca601643306ec2ee0c8a714e8 Mon Sep 17 00:00:00 2001 From: Grisha Vartanyan Date: Wed, 23 Mar 2022 23:07:39 +0100 Subject: [PATCH 03/12] Update syntax tree definition --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/token.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f5c4affdce2d1..75ccbc92be1f6 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1616,7 +1616,7 @@ pub enum StrStyle { /// A raw string, like `r##"foo"##`. /// /// The value is the number of `#` symbols used. - Raw(u16), + Raw(u8), } /// An AST literal. diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index c367573de8a94..b860612f43096 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -60,9 +60,9 @@ pub enum LitKind { Integer, Float, Str, - StrRaw(u16), // raw string delimited by `n` hash symbols + StrRaw(u8), // raw string delimited by `n` hash symbols ByteStr, - ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols + ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols Err, } From 0cf606177e79bc580fa27a82eb9c8b56e7253f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Fri, 25 Mar 2022 11:39:11 +0100 Subject: [PATCH 04/12] Fix double drop of allocator in IntoIter impl of Vec --- library/alloc/src/vec/into_iter.rs | 15 +++++++++------ library/alloc/src/vec/mod.rs | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index f17b8d71b3a1a..471042cd7177e 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -8,7 +8,8 @@ use core::iter::{ FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, }; use core::marker::PhantomData; -use core::mem::{self}; +use core::mem::{self, ManuallyDrop}; +use core::ops::Deref; use core::ptr::{self, NonNull}; use core::slice::{self}; @@ -32,7 +33,9 @@ pub struct IntoIter< pub(super) buf: NonNull, pub(super) phantom: PhantomData, pub(super) cap: usize, - pub(super) alloc: A, + // the drop impl reconstructs a RawVec from buf, cap and alloc + // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop + pub(super) alloc: ManuallyDrop, pub(super) ptr: *const T, pub(super) end: *const T, } @@ -295,11 +298,11 @@ where impl Clone for IntoIter { #[cfg(not(test))] fn clone(&self) -> Self { - self.as_slice().to_vec_in(self.alloc.clone()).into_iter() + self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter() } #[cfg(test)] fn clone(&self) -> Self { - crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter() + crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter() } } @@ -311,8 +314,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { impl Drop for DropGuard<'_, T, A> { fn drop(&mut self) { unsafe { - // `IntoIter::alloc` is not used anymore after this - let alloc = ptr::read(&self.0.alloc); + // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec + let alloc = ManuallyDrop::into_inner(ptr::read(&self.0.alloc)); // RawVec handles deallocation let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 9a66e69bdc061..96857c4bd6ffd 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2575,7 +2575,7 @@ impl IntoIterator for Vec { fn into_iter(self) -> IntoIter { unsafe { let mut me = ManuallyDrop::new(self); - let alloc = ptr::read(me.allocator()); + let alloc = ManuallyDrop::new(ptr::read(me.allocator())); let begin = me.as_mut_ptr(); let end = if mem::size_of::() == 0 { arith_offset(begin as *const i8, me.len() as isize) as *const T From d14c0d2acb3ff1d0111920185109c9697a3cd460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Fri, 25 Mar 2022 13:27:18 +0100 Subject: [PATCH 05/12] Use ManuallyDrop::take instead of into_inner Co-authored-by: Daniel Henry-Mantilla --- library/alloc/src/vec/into_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 471042cd7177e..1f9398faf2267 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -315,7 +315,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { fn drop(&mut self) { unsafe { // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec - let alloc = ManuallyDrop::into_inner(ptr::read(&self.0.alloc)); + let alloc = ManuallyDrop::take(&mut self.0.alloc); // RawVec handles deallocation let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); } From 4b53f563bd5b0f0e9cad26dbf2514f9a72c3fa2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Fri, 25 Mar 2022 13:00:49 +0100 Subject: [PATCH 06/12] Add a test verifying the number of drop calls --- library/alloc/tests/vec.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index ca0fcc855c7b8..ab2414a6dc0b4 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,3 +1,6 @@ +use core::alloc::{Allocator, Layout}; +use core::ptr::NonNull; +use std::alloc::System; use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cell::Cell; @@ -991,6 +994,27 @@ fn test_into_iter_advance_by() { assert_eq!(i.len(), 0); } +#[test] +fn test_into_iter_drop_allocator() { + struct ReferenceCountedAllocator<'a>(DropCounter<'a>); + + unsafe impl Allocator for ReferenceCountedAllocator<'_> { + fn allocate(&self, layout: Layout) -> Result, core::alloc::AllocError> { + System.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + System.deallocate(ptr, layout) + } + } + + let mut drop_count = 0; + let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); + let _ = Vec::::new_in(allocator).into_iter(); + + assert_eq!(drop_count, 1); +} + #[test] fn test_from_iter_specialization() { let src: Vec = vec![0usize; 1]; From c3840c9ea142c80107067869143192498beec3d2 Mon Sep 17 00:00:00 2001 From: Grisha Vartanyan Date: Fri, 25 Mar 2022 15:05:27 +0100 Subject: [PATCH 07/12] Update clippy helper function types --- src/tools/clippy/clippy_lints/src/regex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index b6d04334de9e5..a92097e1d24ca 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for Regex { #[allow(clippy::cast_possible_truncation)] // truncation very unlikely here #[must_use] -fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span { +fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u8) -> Span { let offset = u32::from(offset); let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset); let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset); From d9a438dc73de6ff146ae3e6bc4050b7cea41b09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Fri, 25 Mar 2022 16:57:59 +0100 Subject: [PATCH 08/12] Add another assertion without into_iter --- library/alloc/tests/vec.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index ab2414a6dc0b4..19e39ebf910b5 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1009,10 +1009,14 @@ fn test_into_iter_drop_allocator() { } let mut drop_count = 0; - let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); - let _ = Vec::::new_in(allocator).into_iter(); + let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); + let _ = Vec::::new_in(allocator); assert_eq!(drop_count, 1); + + let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); + let _ = Vec::::new_in(allocator).into_iter(); + assert_eq!(drop_count, 2); } #[test] From 78e27e2c7a85021a0b72253c17d0d99a383e8385 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 16 Mar 2022 15:52:21 +0100 Subject: [PATCH 09/12] async: Give predictable, reserved name to binding generated from .await expressions. This name makes it to debuginfo and allows debuggers to identify such bindings and their captured versions in suspended async fns. --- compiler/rustc_ast_lowering/src/expr.rs | 29 ++++++++++--------- compiler/rustc_span/src/symbol.rs | 2 +- .../codegen/async-fn-debug-awaitee-field.rs | 23 +++++++++++++++ 3 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 src/test/codegen/async-fn-debug-awaitee-field.rs diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d64f1a05712a9..9442e0f1a1f35 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -618,9 +618,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `.await` into: /// ```rust /// match ::std::future::IntoFuture::into_future() { - /// mut pinned => loop { + /// mut __awaitee => loop { /// match unsafe { ::std::future::Future::poll( - /// <::std::pin::Pin>::new_unchecked(&mut pinned), + /// <::std::pin::Pin>::new_unchecked(&mut __awaitee), /// ::std::future::get_context(task_context), /// ) } { /// ::std::task::Poll::Ready(result) => break result, @@ -657,21 +657,24 @@ impl<'hir> LoweringContext<'_, 'hir> { let expr = self.lower_expr_mut(expr); let expr_hir_id = expr.hir_id; - let pinned_ident = Ident::with_dummy_span(sym::pinned); - let (pinned_pat, pinned_pat_hid) = - self.pat_ident_binding_mode(span, pinned_ident, hir::BindingAnnotation::Mutable); + // Note that the name of this binding must not be changed to something else because + // debuggers and debugger extensions expect it to be called `__awaitee`. They use + // this name to identify what is being awaited by a suspended async functions. + let awaitee_ident = Ident::with_dummy_span(sym::__awaitee); + let (awaitee_pat, awaitee_pat_hid) = + self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable); let task_context_ident = Ident::with_dummy_span(sym::_task_context); // unsafe { // ::std::future::Future::poll( - // ::std::pin::Pin::new_unchecked(&mut pinned), + // ::std::pin::Pin::new_unchecked(&mut __awaitee), // ::std::future::get_context(task_context), // ) // } let poll_expr = { - let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid); - let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); + let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid); + let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee); let task_context = if let Some(task_context_hid) = self.task_context { self.expr_ident_mut(span, task_context_ident, task_context_hid) } else { @@ -681,7 +684,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let new_unchecked = self.expr_call_lang_item_fn_mut( span, hir::LangItem::PinNewUnchecked, - arena_vec![self; ref_mut_pinned], + arena_vec![self; ref_mut_awaitee], Some(expr_hir_id), ); let get_context = self.expr_call_lang_item_fn_mut( @@ -782,8 +785,8 @@ impl<'hir> LoweringContext<'_, 'hir> { span: self.lower_span(span), }); - // mut pinned => loop { ... } - let pinned_arm = self.arm(pinned_pat, loop_expr); + // mut __awaitee => loop { ... } + let awaitee_arm = self.arm(awaitee_pat, loop_expr); // `match ::std::future::IntoFuture::into_future() { ... }` let into_future_span = self.mark_span_with_reason( @@ -799,11 +802,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // match { - // mut pinned => loop { .. } + // mut __awaitee => loop { .. } // } hir::ExprKind::Match( into_future_expr, - arena_vec![self; pinned_arm], + arena_vec![self; awaitee_arm], hir::MatchSource::AwaitDesugar, ) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4dd1c3fed6b36..774cf6a19c76d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -272,6 +272,7 @@ symbols! { __D, __H, __S, + __awaitee, __try_var, _d, _e, @@ -1022,7 +1023,6 @@ symbols! { pattern_parentheses, phantom_data, pin, - pinned, platform_intrinsics, plugin, plugin_registrar, diff --git a/src/test/codegen/async-fn-debug-awaitee-field.rs b/src/test/codegen/async-fn-debug-awaitee-field.rs new file mode 100644 index 0000000000000..efb345fa9f3e5 --- /dev/null +++ b/src/test/codegen/async-fn-debug-awaitee-field.rs @@ -0,0 +1,23 @@ +// This test makes sure that the generator field capturing the awaitee in a `.await` expression +// is called "__awaitee" in debuginfo. This name must not be changed since debuggers and debugger +// extensions rely on the field having this name. + +// ignore-tidy-linelength +// compile-flags: -C debuginfo=2 --edition=2018 + +async fn foo() {} + +async fn async_fn_test() { + foo().await; +} + +// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", +// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum$", +// CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]], +// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture", +// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture >", + +fn main() { + let _fn = async_fn_test(); +} From 759d1e6af8610cdfdbf091a5d3d825b05c1fc6a2 Mon Sep 17 00:00:00 2001 From: Grisha Vartanyan Date: Wed, 30 Mar 2022 18:20:30 +0200 Subject: [PATCH 10/12] Update error message & remove outdated test comment --- compiler/rustc_parse/src/lexer/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 601a39e69ab9d..d688d37c1cf3d 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -589,15 +589,13 @@ impl<'a> StringReader<'a> { } } - /// Note: It was decided to not add a test case, because it would be too big. - /// fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! { self.fatal_span_( start, self.pos, &format!( "too many `#` symbols: raw strings may be delimited \ - by up to 65535 `#` symbols, but found {}", + by up to 255 `#` symbols, but found {}", found ), ) From 1004783ef9bdcf006f0ed33badacf83a5934feb2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 11 Feb 2022 15:08:35 +0800 Subject: [PATCH 11/12] Stabilize native library modifier syntax and the `whole-archive` modifier specifically --- compiler/rustc_ast_passes/src/feature_gate.rs | 8 -- compiler/rustc_codegen_ssa/src/back/link.rs | 103 +++++++++++------- compiler/rustc_codegen_ssa/src/back/linker.rs | 11 ++ compiler/rustc_feature/src/accepted.rs | 4 + compiler/rustc_feature/src/active.rs | 4 - compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 42 ++++++- compiler/rustc_session/src/config.rs | 63 +++++++---- compiler/rustc_session/src/cstore.rs | 6 + compiler/rustc_session/src/utils.rs | 20 ++++ library/unwind/src/lib.rs | 2 +- src/doc/rustc/src/command-line-arguments.md | 26 ++++- .../native-link-modifiers-whole-archive.md | 18 --- .../native-link-modifiers.md | 11 -- .../native_lib_in_src.rs | 2 - src/test/run-make/raw-dylib-c/lib.rs | 2 +- .../feature-gate-native_link_modifiers.rs | 5 - .../feature-gate-native_link_modifiers.stderr | 12 -- ...re-gate-native_link_modifiers_as_needed.rs | 3 - ...ate-native_link_modifiers_as_needed.stderr | 2 +- ...ure-gate-native_link_modifiers_bundle-2.rs | 1 - ...gate-native_link_modifiers_bundle-3.stderr | 2 +- ...ature-gate-native_link_modifiers_bundle.rs | 3 - ...e-gate-native_link_modifiers_bundle.stderr | 2 +- ...ure-gate-native_link_modifiers_verbatim.rs | 3 - ...gate-native_link_modifiers_verbatim.stderr | 2 +- ...ate-native_link_modifiers_whole_archive.rs | 8 -- ...native_link_modifiers_whole_archive.stderr | 12 -- .../mix-bundle-and-whole-archive-link-attr.rs | 2 - .../modifiers-override-2.rs | 3 + .../modifiers-override-2.stderr | 2 + .../modifiers-override.rs | 17 +++ .../modifiers-override.stderr | 32 ++++++ 33 files changed, 270 insertions(+), 165 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md delete mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers.md delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr create mode 100644 src/test/ui/native-library-link-flags/modifiers-override-2.rs create mode 100644 src/test/ui/native-library-link-flags/modifiers-override-2.stderr create mode 100644 src/test/ui/native-library-link-flags/modifiers-override.rs create mode 100644 src/test/ui/native-library-link-flags/modifiers-override.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5b6147c72230d..a778d8c547084 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -387,13 +387,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if attr.has_name(sym::link) { for nested_meta in attr.meta_item_list().unwrap_or_default() { if nested_meta.has_name(sym::modifiers) { - gate_feature_post!( - self, - native_link_modifiers, - nested_meta.span(), - "native link modifiers are experimental" - ); - if let Some(modifiers) = nested_meta.value_str() { for modifier in modifiers.as_str().split(',') { if let Some(modifier) = modifier.strip_prefix(&['+', '-']) { @@ -412,7 +405,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_modifier!( "bundle" => native_link_modifiers_bundle "verbatim" => native_link_modifiers_verbatim - "whole-archive" => native_link_modifiers_whole_archive "as-needed" => native_link_modifiers_as_needed ); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index dbbbbd5ecc020..548ae0e411da7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1844,7 +1844,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // This change is somewhat breaking in practice due to local static libraries being linked // as whole-archive (#85144), so removing whole-archive may be a pre-requisite. if sess.opts.debugging_opts.link_native_libraries { - add_local_native_libraries(cmd, sess, codegen_results); + add_local_native_libraries(cmd, sess, codegen_results, crate_type); } // Upstream rust libraries and their nobundle static libraries @@ -2016,6 +2016,16 @@ fn add_order_independent_options( add_rpath_args(cmd, sess, codegen_results, out_filename); } +// A dylib may reexport symbols from the linked rlib or native static library. +// Even if some symbol is reexported it's still not necessarily counted as used and may be +// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static +// libraries as whole-archive to avoid losing reexported symbols. +// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive. +fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool { + crate_type == CrateType::Dylib + && !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol()) +} + /// # Native library linking /// /// User-supplied library search paths (-L on the command line). These are the same paths used to @@ -2029,6 +2039,7 @@ fn add_local_native_libraries( cmd: &mut dyn Linker, sess: &Session, codegen_results: &CodegenResults, + crate_type: CrateType, ) { let filesearch = sess.target_filesearch(PathKind::All); for search_path in filesearch.search_paths() { @@ -2046,14 +2057,18 @@ fn add_local_native_libraries( codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l)); let search_path = OnceCell::new(); - let mut last = (NativeLibKind::Unspecified, None); + let mut last = (None, NativeLibKind::Unspecified, None); for lib in relevant_libs { let Some(name) = lib.name else { continue; }; // Skip if this library is the same as the last. - last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; + last = if (lib.name, lib.kind, lib.verbatim) == last { + continue; + } else { + (lib.name, lib.kind, lib.verbatim) + }; let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { @@ -2064,15 +2079,19 @@ fn add_local_native_libraries( NativeLibKind::Framework { as_needed } => { cmd.link_framework(name, as_needed.unwrap_or(true)) } - NativeLibKind::Static { bundle: None | Some(true), .. } - | NativeLibKind::Static { whole_archive: Some(true), .. } => { - cmd.link_whole_staticlib( - name, - verbatim, - &search_path.get_or_init(|| archive_search_paths(sess)), - ); + NativeLibKind::Static { whole_archive, .. } => { + if whole_archive == Some(true) + || (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd)) + { + cmd.link_whole_staticlib( + name, + verbatim, + &search_path.get_or_init(|| archive_search_paths(sess)), + ); + } else { + cmd.link_staticlib(name, verbatim) + } } - NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim), NativeLibKind::RawDylib => { // FIXME(#58713): Proper handling for raw dylibs. bug!("raw_dylib feature not yet implemented"); @@ -2197,34 +2216,37 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // external build system already has the native dependencies defined, and it // will provide them to the linker itself. if sess.opts.debugging_opts.link_native_libraries { - let mut last = None; + let mut last = (None, NativeLibKind::Unspecified, None); for lib in &codegen_results.crate_info.native_libraries[&cnum] { + let Some(name) = lib.name else { + continue; + }; if !relevant_lib(sess, lib) { - // Skip libraries if they are disabled by `#[link(cfg=...)]` continue; } // Skip if this library is the same as the last. - if last == lib.name { + last = if (lib.name, lib.kind, lib.verbatim) == last { continue; - } - - if let Some(static_lib_name) = lib.name { - if let NativeLibKind::Static { bundle: Some(false), whole_archive } = - lib.kind + } else { + (lib.name, lib.kind, lib.verbatim) + }; + + if let NativeLibKind::Static { bundle: Some(false), whole_archive } = + lib.kind + { + let verbatim = lib.verbatim.unwrap_or(false); + if whole_archive == Some(true) + || (whole_archive == None + && default_to_whole_archive(sess, crate_type, cmd)) { - let verbatim = lib.verbatim.unwrap_or(false); - if whole_archive == Some(true) { - cmd.link_whole_staticlib( - static_lib_name, - verbatim, - search_path.get_or_init(|| archive_search_paths(sess)), - ); - } else { - cmd.link_staticlib(static_lib_name, verbatim); - } - - last = lib.name; + cmd.link_whole_staticlib( + name, + verbatim, + search_path.get_or_init(|| archive_search_paths(sess)), + ); + } else { + cmd.link_staticlib(name, verbatim); } } } @@ -2282,15 +2304,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let cratepath = &src.rlib.as_ref().unwrap().0; let mut link_upstream = |path: &Path| { - // If we're creating a dylib, then we need to include the - // whole of each object in our archive into that artifact. This is - // because a `dylib` can be reused as an intermediate artifact. - // - // Note, though, that we don't want to include the whole of a - // compiler-builtins crate (e.g., compiler-rt) because it'll get - // repeatedly linked anyway. + // We don't want to include the whole compiler-builtins crate (e.g., compiler-rt) + // regardless of the default because it'll get repeatedly linked anyway. let path = fix_windows_verbatim_for_gcc(path); - if crate_type == CrateType::Dylib + if default_to_whole_archive(sess, crate_type, cmd) && codegen_results.crate_info.compiler_builtins != Some(cnum) { cmd.link_whole_rlib(&path); @@ -2401,7 +2418,7 @@ fn add_upstream_native_libraries( sess: &Session, codegen_results: &CodegenResults, ) { - let mut last = (NativeLibKind::Unspecified, None); + let mut last = (None, NativeLibKind::Unspecified, None); for &cnum in &codegen_results.crate_info.used_crates { for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { let Some(name) = lib.name else { @@ -2412,7 +2429,11 @@ fn add_upstream_native_libraries( } // Skip if this library is the same as the last. - last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; + last = if (lib.name, lib.kind, lib.verbatim) == last { + continue; + } else { + (lib.name, lib.kind, lib.verbatim) + }; let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a838787381d3f..3a66bfafaf3f4 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -186,6 +186,9 @@ pub trait Linker { fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); + fn exported_symbol_means_used_symbol(&self) -> bool { + true + } fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); fn group_end(&mut self); @@ -724,6 +727,10 @@ impl<'a> Linker for GccLinker<'a> { } } + fn exported_symbol_means_used_symbol(&self) -> bool { + self.sess.target.is_like_windows || self.sess.target.is_like_osx + } + fn subsystem(&mut self, subsystem: &str) { self.linker_arg("--subsystem"); self.linker_arg(&subsystem); @@ -1471,6 +1478,10 @@ impl<'a> Linker for L4Bender<'a> { return; } + fn exported_symbol_means_used_symbol(&self) -> bool { + false + } + fn subsystem(&mut self, subsystem: &str) { self.cmd.arg(&format!("--subsystem {}", subsystem)); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ace0c9df58d50..e37251c9c2439 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -215,6 +215,10 @@ declare_features! ( /// Allows patterns with concurrent by-move and by-ref bindings. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.49.0", Some(68354), None), + /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` + (accepted, native_link_modifiers, "1.61.0", Some(81490), None), + /// Allows specifying the whole-archive link modifier + (accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None), /// Allows using `#![no_std]`. (accepted, no_std, "1.6.0", None, None), /// Allows defining identifiers beyond ASCII. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index feef7295254a9..90b35b5a83fb5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -446,16 +446,12 @@ declare_features! ( (active, must_not_suspend, "1.57.0", Some(83310), None), /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), - /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` - (active, native_link_modifiers, "1.53.0", Some(81490), None), /// Allows specifying the as-needed link modifier (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), /// Allows specifying the bundle link modifier (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None), /// Allows specifying the verbatim link modifier (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None), - /// Allows specifying the whole-archive link modifier - (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None), /// Allow negative trait implementations. (active, negative_impls, "1.44.0", Some(68318), None), /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8476c2bfcc431..0324ac3641e11 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,5 +1,5 @@ #![feature(nll)] -#![feature(native_link_modifiers)] +#![cfg_attr(bootstrap, feature(native_link_modifiers))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c3a7611239139..1cbfb0bd5546b 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -125,13 +125,18 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { // Do this outside the above loop so we don't depend on modifiers coming // after kinds - if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) { + let mut modifiers_count = 0; + for item in items.iter().filter(|item| item.has_name(sym::modifiers)) { if let Some(modifiers) = item.value_str() { + modifiers_count += 1; let span = item.name_value_literal_span().unwrap(); + let mut has_duplicate_modifiers = false; for modifier in modifiers.as_str().split(',') { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { Some(m) => (m, modifier.starts_with('+')), None => { + // Note: this error also excludes the case with empty modifier + // string, like `modifiers = ""`. sess.span_err( span, "invalid linking modifier syntax, expected '+' or '-' prefix \ @@ -143,6 +148,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { match (modifier, &mut lib.kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => { + if bundle.is_some() { + has_duplicate_modifiers = true; + } *bundle = Some(value); } ("bundle", _) => { @@ -153,9 +161,17 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { ); } - ("verbatim", _) => lib.verbatim = Some(value), + ("verbatim", _) => { + if lib.verbatim.is_some() { + has_duplicate_modifiers = true; + } + lib.verbatim = Some(value); + } ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + if whole_archive.is_some() { + has_duplicate_modifiers = true; + } *whole_archive = Some(value); } ("whole-archive", _) => { @@ -168,6 +184,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { ("as-needed", NativeLibKind::Dylib { as_needed }) | ("as-needed", NativeLibKind::Framework { as_needed }) => { + if as_needed.is_some() { + has_duplicate_modifiers = true; + } *as_needed = Some(value); } ("as-needed", _) => { @@ -190,12 +209,22 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { } } } + if has_duplicate_modifiers { + let msg = + "same modifier is used multiple times in a single `modifiers` argument"; + sess.span_err(item.span(), msg); + } } else { let msg = "must be of the form `#[link(modifiers = \"...\")]`"; sess.span_err(item.span(), msg); } } + if modifiers_count > 1 { + let msg = "multiple `modifiers` arguments in a single `#[link]` attribute"; + sess.span_err(m.span, msg); + } + // In general we require #[link(name = "...")] but we allow // #[link(wasm_import_module = "...")] without the `name`. let requires_name = kind_specified || lib.wasm_import_module.is_none(); @@ -349,6 +378,15 @@ impl Collector<'_> { .drain_filter(|lib| { if let Some(lib_name) = lib.name { if lib_name.as_str() == passed_lib.name { + // FIXME: This whole logic is questionable, whether modifiers are + // involved or not, library reordering and kind overriding without + // explicit `:rename` in particular. + if lib.has_modifiers() || passed_lib.has_modifiers() { + self.tcx.sess.span_err( + self.tcx.def_span(lib.foreign_module.unwrap()), + "overriding linking modifiers from command line is not supported" + ); + } if passed_lib.kind != NativeLibKind::Unspecified { lib.kind = passed_lib.kind; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 44a2e2bdc85d3..856436e44dbc8 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1948,9 +1948,6 @@ fn parse_native_lib_kind( kind: &str, error_format: ErrorOutputType, ) -> (NativeLibKind, Option) { - let is_nightly = nightly_options::match_is_nightly_build(matches); - let enable_unstable = nightly_options::is_unstable_enabled(matches); - let (kind, modifiers) = match kind.split_once(':') { None => (kind, None), Some((kind, modifiers)) => (kind, Some(modifiers)), @@ -1972,7 +1969,7 @@ fn parse_native_lib_kind( "linking modifier can't be used with library kind `static-nobundle`", ) } - if !is_nightly { + if !nightly_options::match_is_nightly_build(matches) { early_error( error_format, "library kind `static-nobundle` are currently unstable and only accepted on \ @@ -1988,23 +1985,7 @@ fn parse_native_lib_kind( }; match modifiers { None => (kind, None), - Some(modifiers) => { - if !is_nightly { - early_error( - error_format, - "linking modifiers are currently unstable and only accepted on \ - the nightly compiler", - ); - } - if !enable_unstable { - early_error( - error_format, - "linking modifiers are currently unstable, \ - the `-Z unstable-options` flag must also be passed to use it", - ) - } - parse_native_lib_modifiers(kind, modifiers, error_format) - } + Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches), } } @@ -2012,7 +1993,23 @@ fn parse_native_lib_modifiers( mut kind: NativeLibKind, modifiers: &str, error_format: ErrorOutputType, + matches: &getopts::Matches, ) -> (NativeLibKind, Option) { + let report_unstable_modifier = |modifier| { + if !nightly_options::is_unstable_enabled(matches) { + let why = if nightly_options::match_is_nightly_build(matches) { + " and only accepted on the nightly compiler" + } else { + ", the `-Z unstable-options` flag must also be passed to use it" + }; + early_error( + error_format, + &format!("{modifier} linking modifier is currently unstable{why}"), + ) + } + }; + + let mut has_duplicate_modifiers = false; let mut verbatim = None; for modifier in modifiers.split(',') { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { @@ -2026,6 +2023,10 @@ fn parse_native_lib_modifiers( match (modifier, &mut kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => { + report_unstable_modifier(modifier); + if bundle.is_some() { + has_duplicate_modifiers = true; + } *bundle = Some(value); } ("bundle", _) => early_error( @@ -2034,9 +2035,18 @@ fn parse_native_lib_modifiers( `static` linking kind", ), - ("verbatim", _) => verbatim = Some(value), + ("verbatim", _) => { + report_unstable_modifier(modifier); + if verbatim.is_some() { + has_duplicate_modifiers = true; + } + verbatim = Some(value); + } ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + if whole_archive.is_some() { + has_duplicate_modifiers = true; + } *whole_archive = Some(value); } ("whole-archive", _) => early_error( @@ -2047,6 +2057,10 @@ fn parse_native_lib_modifiers( ("as-needed", NativeLibKind::Dylib { as_needed }) | ("as-needed", NativeLibKind::Framework { as_needed }) => { + report_unstable_modifier(modifier); + if as_needed.is_some() { + has_duplicate_modifiers = true; + } *as_needed = Some(value); } ("as-needed", _) => early_error( @@ -2055,6 +2069,8 @@ fn parse_native_lib_modifiers( `dylib` and `framework` linking kinds", ), + // Note: this error also excludes the case with empty modifier + // string, like `modifiers = ""`. _ => early_error( error_format, &format!( @@ -2064,6 +2080,9 @@ fn parse_native_lib_modifiers( ), } } + if has_duplicate_modifiers { + report_unstable_modifier("duplicating") + } (kind, verbatim) } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 281fc887633d9..c1fd3c7c61b9e 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -75,6 +75,12 @@ pub struct NativeLib { pub dll_imports: Vec, } +impl NativeLib { + pub fn has_modifiers(&self) -> bool { + self.verbatim.is_some() || self.kind.has_modifiers() + } +} + #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct DllImport { pub name: Symbol, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index a33f94013d24c..6a8775bd10b7e 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -43,6 +43,20 @@ pub enum NativeLibKind { Unspecified, } +impl NativeLibKind { + pub fn has_modifiers(&self) -> bool { + match self { + NativeLibKind::Static { bundle, whole_archive } => { + bundle.is_some() || whole_archive.is_some() + } + NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => { + as_needed.is_some() + } + NativeLibKind::RawDylib | NativeLibKind::Unspecified => false, + } + } +} + rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind); #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] @@ -53,6 +67,12 @@ pub struct NativeLib { pub verbatim: Option, } +impl NativeLib { + pub fn has_modifiers(&self) -> bool { + self.verbatim.is_some() || self.kind.has_modifiers() + } +} + rustc_data_structures::impl_stable_hash_via_hash!(NativeLib); /// A path that has been canonicalized along with its original, non-canonicalized form diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 079626f0fea54..82f1e63f4b54f 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] #![feature(link_cfg)] -#![feature(native_link_modifiers)] +#![cfg_attr(bootstrap, feature(native_link_modifiers))] #![feature(native_link_modifiers_bundle)] #![feature(nll)] #![feature(staged_api)] diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 3759cb632bb3f..7838696cc128b 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -37,6 +37,8 @@ KIND=PATH` where `KIND` may be one of: ## `-l`: link the generated crate to a native library +Syntax: `-l [KIND[:MODIFIERS]=]NAME[:RENAME]`. + This flag allows you to specify linking to a specific native library when building a crate. @@ -47,7 +49,13 @@ where `KIND` may be one of: - `static` — A native static library (such as a `.a` archive). - `framework` — A macOS framework. -The kind of library can be specified in a [`#[link]` +If the kind is specified, then linking modifiers can be attached to it. +Modifiers are specified as a comma-delimited string with each modifier prefixed with +either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. +The last boolean value specified for a given modifier wins. \ +Example: `-l static:+whole-archive=mylib`. + +The kind of library and the modifiers can also be specified in a [`#[link]` attribute][link-attribute]. If the kind is not specified in the `link` attribute or on the command-line, it will link a dynamic library if available, otherwise it will use a static library. If the kind is specified on the @@ -59,6 +67,22 @@ and `LINK_NAME` is the name of the actual library that will be linked. [link-attribute]: ../reference/items/external-blocks.html#the-link-attribute +### Linking modifiers: `whole-archive` + +This modifier is only compatible with the `static` linking kind. +Using any other kind will result in a compiler error. + +`+whole-archive` means that the static library is linked as a whole archive +without throwing any object files away. + +This modifier translates to `--whole-archive` for `ld`-like linkers, +to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`. +The modifier does nothing for linkers that don't support it. + +The default for this modifier is `-whole-archive`. \ +NOTE: The default may currently be different when building dylibs for some targets, +but it is not guaranteed. + ## `--crate-type`: a list of types of crates for the compiler to emit diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md deleted file mode 100644 index 4961e88cad1e0..0000000000000 --- a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md +++ /dev/null @@ -1,18 +0,0 @@ -# `native_link_modifiers_whole_archive` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier. - -Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. - -`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away. - -This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`. -The modifier does nothing for linkers that don't support it. - -The default for this modifier is `-whole-archive`. diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers.md b/src/doc/unstable-book/src/language-features/native-link-modifiers.md deleted file mode 100644 index fc8b575462175..0000000000000 --- a/src/doc/unstable-book/src/language-features/native-link-modifiers.md +++ /dev/null @@ -1,11 +0,0 @@ -# `native_link_modifiers` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute. - -Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins. diff --git a/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs b/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs index 373d89b7936e5..2436c36e6ebfb 100644 --- a/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs +++ b/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs @@ -1,6 +1,4 @@ #![feature(native_link_modifiers_bundle)] -#![feature(native_link_modifiers_whole_archive)] -#![feature(native_link_modifiers)] use std::io::Write; diff --git a/src/test/run-make/raw-dylib-c/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs index d8e6301f38eb8..e185c4aec12b0 100644 --- a/src/test/run-make/raw-dylib-c/lib.rs +++ b/src/test/run-make/raw-dylib-c/lib.rs @@ -1,4 +1,4 @@ -#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)] +#![feature(raw_dylib, native_link_modifiers_verbatim)] #[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")] extern { diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs deleted file mode 100644 index 2d00aa2a3cfcb..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[link(name = "foo", modifiers = "")] -//~^ ERROR: native link modifiers are experimental -extern "C" {} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr deleted file mode 100644 index 20a2d6a26fa57..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: native link modifiers are experimental - --> $DIR/feature-gate-native_link_modifiers.rs:1:22 - | -LL | #[link(name = "foo", modifiers = "")] - | ^^^^^^^^^^^^^^ - | - = note: see issue #81490 for more information - = help: add `#![feature(native_link_modifiers)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs index 4cf8067592ec2..fedee8123980e 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs @@ -1,6 +1,3 @@ -#![allow(incomplete_features)] -#![feature(native_link_modifiers)] - #[link(name = "foo", modifiers = "+as-needed")] //~^ ERROR: `#[link(modifiers="as-needed")]` is unstable extern "C" {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr index 08ce807851b38..96750aa6e808a 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr @@ -1,5 +1,5 @@ error[E0658]: `#[link(modifiers="as-needed")]` is unstable - --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:4:34 + --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:34 | LL | #[link(name = "foo", modifiers = "+as-needed")] | ^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs index 1b5fa78ee5521..e229564950fcf 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-2.rs @@ -1,7 +1,6 @@ // Test native_link_modifiers_bundle don't need static-nobundle // check-pass -#![feature(native_link_modifiers)] #![feature(native_link_modifiers_bundle)] #[link(name = "foo", kind = "static", modifiers = "-bundle")] diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr index 86ccb4e860b69..900605c3b375b 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr @@ -1,2 +1,2 @@ -error: linking modifiers are currently unstable, the `-Z unstable-options` flag must also be passed to use it +error: bundle linking modifier is currently unstable and only accepted on the nightly compiler diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs index b2b1dc28e47b9..c3c3cff17c403 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs @@ -1,6 +1,3 @@ -#![allow(incomplete_features)] -#![feature(native_link_modifiers)] - #[link(name = "foo", modifiers = "+bundle")] //~^ ERROR: `#[link(modifiers="bundle")]` is unstable extern "C" {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr index b3e22b0644aa8..984b90d9b6c2e 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr @@ -1,5 +1,5 @@ error[E0658]: `#[link(modifiers="bundle")]` is unstable - --> $DIR/feature-gate-native_link_modifiers_bundle.rs:4:34 + --> $DIR/feature-gate-native_link_modifiers_bundle.rs:1:34 | LL | #[link(name = "foo", modifiers = "+bundle")] | ^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs index 042ce0b3f65b2..57527be1112cb 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs @@ -1,6 +1,3 @@ -#![allow(incomplete_features)] -#![feature(native_link_modifiers)] - #[link(name = "foo", modifiers = "+verbatim")] //~^ ERROR: `#[link(modifiers="verbatim")]` is unstable extern "C" {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr index 8159416edfa3d..5c64c0d21bdb4 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr @@ -1,5 +1,5 @@ error[E0658]: `#[link(modifiers="verbatim")]` is unstable - --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:4:34 + --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:1:34 | LL | #[link(name = "foo", modifiers = "+verbatim")] | ^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs deleted file mode 100644 index ca801e5911432..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![allow(incomplete_features)] -#![feature(native_link_modifiers)] - -#[link(name = "foo", modifiers = "+whole-archive")] -//~^ ERROR: `#[link(modifiers="whole-archive")]` is unstable -extern "C" {} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr deleted file mode 100644 index cacaa789ecb79..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[link(modifiers="whole-archive")]` is unstable - --> $DIR/feature-gate-native_link_modifiers_whole_archive.rs:4:34 - | -LL | #[link(name = "foo", modifiers = "+whole-archive")] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #81490 for more information - = help: add `#![feature(native_link_modifiers_whole_archive)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs b/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs index c3714a3845180..b153ef94626a3 100644 --- a/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs +++ b/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs @@ -2,9 +2,7 @@ // build-fail // error-pattern: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs -#![feature(native_link_modifiers)] #![feature(native_link_modifiers_bundle)] -#![feature(native_link_modifiers_whole_archive)] #[link(name = "mylib", kind = "static", modifiers = "+bundle,+whole-archive")] extern "C" { } diff --git a/src/test/ui/native-library-link-flags/modifiers-override-2.rs b/src/test/ui/native-library-link-flags/modifiers-override-2.rs new file mode 100644 index 0000000000000..333f6786b0fba --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override-2.rs @@ -0,0 +1,3 @@ +// compile-flags:-lstatic:+whole-archive,-whole-archive=foo + +fn main() {} diff --git a/src/test/ui/native-library-link-flags/modifiers-override-2.stderr b/src/test/ui/native-library-link-flags/modifiers-override-2.stderr new file mode 100644 index 0000000000000..9200d7bfb0ce3 --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override-2.stderr @@ -0,0 +1,2 @@ +error: duplicating linking modifier is currently unstable and only accepted on the nightly compiler + diff --git a/src/test/ui/native-library-link-flags/modifiers-override.rs b/src/test/ui/native-library-link-flags/modifiers-override.rs new file mode 100644 index 0000000000000..f6d770559e6e0 --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override.rs @@ -0,0 +1,17 @@ +// compile-flags:-ldylib:+as-needed=foo -lstatic=bar -Zunstable-options + +#![feature(native_link_modifiers_bundle)] + +#[link(name = "foo")] +#[link( //~ ERROR multiple `modifiers` arguments in a single `#[link]` attribute + name = "bar", + kind = "static", + modifiers = "+whole-archive,-whole-archive", + //~^ ERROR same modifier is used multiple times in a single `modifiers` argument + modifiers = "+bundle" +)] +extern "C" {} +//~^ ERROR overriding linking modifiers from command line is not supported +//~| ERROR overriding linking modifiers from command line is not supported + +fn main() {} diff --git a/src/test/ui/native-library-link-flags/modifiers-override.stderr b/src/test/ui/native-library-link-flags/modifiers-override.stderr new file mode 100644 index 0000000000000..8644d2382d2ba --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override.stderr @@ -0,0 +1,32 @@ +error: same modifier is used multiple times in a single `modifiers` argument + --> $DIR/modifiers-override.rs:9:5 + | +LL | modifiers = "+whole-archive,-whole-archive", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: multiple `modifiers` arguments in a single `#[link]` attribute + --> $DIR/modifiers-override.rs:6:1 + | +LL | / #[link( +LL | | name = "bar", +LL | | kind = "static", +LL | | modifiers = "+whole-archive,-whole-archive", +LL | | +LL | | modifiers = "+bundle" +LL | | )] + | |__^ + +error: overriding linking modifiers from command line is not supported + --> $DIR/modifiers-override.rs:13:1 + | +LL | extern "C" {} + | ^^^^^^^^^^^^^ + +error: overriding linking modifiers from command line is not supported + --> $DIR/modifiers-override.rs:13:1 + | +LL | extern "C" {} + | ^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From 4e570a68a158b6592fc00f3c6e21efda84992079 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Fri, 11 Mar 2022 18:46:49 -0500 Subject: [PATCH 12/12] Add the generic_associated_types_extended feature --- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_middle/src/ty/fold.rs | 47 ++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/auto_trait.rs | 9 ++- .../src/traits/fulfill.rs | 12 +-- .../src/traits/project.rs | 76 ++++++++++++++----- .../src/traits/select/mod.rs | 9 ++- ...-gate-generic_associated_types_extended.rs | 6 ++ ...e-generic_associated_types_extended.stderr | 11 +++ .../extended/lending_iterator.base.nll.stderr | 12 +++ .../extended/lending_iterator.base.stderr | 26 +++++++ .../extended/lending_iterator.rs | 40 ++++++++++ .../extended/lending_iterator_2.base.stderr | 12 +++ .../extended/lending_iterator_2.rs | 31 ++++++++ 14 files changed, 261 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs create mode 100644 src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr create mode 100644 src/test/ui/generic-associated-types/extended/lending_iterator.base.nll.stderr create mode 100644 src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr create mode 100644 src/test/ui/generic-associated-types/extended/lending_iterator.rs create mode 100644 src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr create mode 100644 src/test/ui/generic-associated-types/extended/lending_iterator_2.rs diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index feef7295254a9..da52388654a87 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -400,6 +400,8 @@ declare_features! ( (active, generic_arg_infer, "1.55.0", Some(85077), None), /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). (active, generic_associated_types, "1.23.0", Some(44265), None), + /// An extension to the `generic_associated_types` feature, allowing incomplete features. + (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers (incomplete, generic_const_exprs, "1.56.0", Some(76560), None), /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern. diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 780d380da365e..b799d7a2e8663 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1383,3 +1383,50 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { ControlFlow::CONTINUE } } + +/// Finds the max universe present +pub struct MaxUniverse { + max_universe: ty::UniverseIndex, +} + +impl MaxUniverse { + pub fn new() -> Self { + MaxUniverse { max_universe: ty::UniverseIndex::ROOT } + } + + pub fn max_universe(self) -> ty::UniverseIndex { + self.max_universe + } +} + +impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if let ty::Placeholder(placeholder) = t.kind() { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow { + if let ty::ConstKind::Placeholder(placeholder) = c.val() { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + c.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + if let ty::RePlaceholder(placeholder) = *r { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5cf362bfa7e98..e4153d743427e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -726,6 +726,7 @@ symbols! { generators, generic_arg_infer, generic_associated_types, + generic_associated_types_extended, generic_const_exprs, generic_param_attrs, get_context, diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index ee9983ee8b8d8..63c5682f45e62 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -5,6 +5,7 @@ use super::*; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; +use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{Region, RegionVid, Term}; @@ -751,7 +752,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { debug!("Projecting and unifying projection predicate {:?}", predicate); match project::poly_project_and_unify_type(select, &obligation.with(p)) { - Err(e) => { + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { debug!( "evaluate_nested_obligations: Unable to unify predicate \ '{:?}' '{:?}', bailing out", @@ -759,11 +760,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { ); return false; } - Ok(Err(project::InProgress)) => { + ProjectAndUnifyResult::Recursive => { debug!("evaluate_nested_obligations: recursive projection predicate"); return false; } - Ok(Ok(Some(v))) => { + ProjectAndUnifyResult::Holds(v) => { // We only care about sub-obligations // when we started out trying to unify // some inference variables. See the comment above @@ -782,7 +783,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } } - Ok(Ok(None)) => { + ProjectAndUnifyResult::FailedNormalization => { // It's ok not to make progress when have no inference variables - // in that case, we were only performing unifcation to check if an // error occurred (which would indicate that it's impossible for our diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1b8628344671d..d0b8b0281c5bf 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; use super::const_evaluatable; -use super::project; +use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::wf; use super::CodeAmbiguity; @@ -753,8 +753,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } match project::poly_project_and_unify_type(self.selcx, &project_obligation) { - Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), - Ok(Ok(None)) => { + ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), + ProjectAndUnifyResult::FailedNormalization => { stalled_on.clear(); stalled_on.extend(substs_infer_vars( self.selcx, @@ -763,10 +763,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ProcessResult::Unchanged } // Let the caller handle the recursion - Ok(Err(project::InProgress)) => ProcessResult::Changed(mk_pending(vec![ + ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![ project_obligation.with(project_obligation.predicate.to_predicate(tcx)), ])), - Err(e) => ProcessResult::Error(CodeProjectionError(e)), + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { + ProcessResult::Error(CodeProjectionError(e)) + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index b61e68735712b..b756c57e2f518 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -28,7 +28,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::traits::select::OverflowError; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -144,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { } } +/// Takes the place of a +/// Result< +/// Result>>, InProgress>, +/// MismatchedProjectionTypes<'tcx>, +/// > +pub(super) enum ProjectAndUnifyResult<'tcx> { + Holds(Vec>), + FailedNormalization, + Recursive, + MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), +} + /// Evaluates constraints of the form: /// /// for<...> ::U == V @@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &PolyProjectionObligation<'tcx>, -) -> Result< - Result>>, InProgress>, - MismatchedProjectionTypes<'tcx>, -> { +) -> ProjectAndUnifyResult<'tcx> { let infcx = selcx.infcx(); - infcx.commit_if_ok(|_snapshot| { + let r = infcx.commit_if_ok(|_snapshot| { + let old_universe = infcx.universe(); let placeholder_predicate = infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let new_universe = infcx.universe(); let placeholder_obligation = obligation.with(placeholder_predicate); - let result = project_and_unify_type(selcx, &placeholder_obligation)?; - Ok(result) - }) + match project_and_unify_type(selcx, &placeholder_obligation) { + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e), + ProjectAndUnifyResult::Holds(obligations) + if old_universe != new_universe + && selcx.tcx().features().generic_associated_types_extended => + { + // If the `generic_associated_types_extended` feature is active, then we ignore any + // obligations references lifetimes from any universe greater than or equal to the + // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`, + // which isn't quite what we want. Ideally, we want either an implied + // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we + // substitute concrete regions. There is design work to be done here; until then, + // however, this allows experimenting potential GAT features without running into + // well-formedness issues. + let new_obligations = obligations + .into_iter() + .filter(|obligation| { + let mut visitor = MaxUniverse::new(); + obligation.predicate.visit_with(&mut visitor); + visitor.max_universe() < new_universe + }) + .collect(); + Ok(ProjectAndUnifyResult::Holds(new_obligations)) + } + other => Ok(other), + } + }); + + match r { + Ok(inner) => inner, + Err(err) => ProjectAndUnifyResult::MismatchedProjectionTypes(err), + } } /// Evaluates constraints of the form: @@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_type] for an explanation of the return value. +#[tracing::instrument(level = "debug", skip(selcx))] fn project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionObligation<'tcx>, -) -> Result< - Result>>, InProgress>, - MismatchedProjectionTypes<'tcx>, -> { - debug!(?obligation, "project_and_unify_type"); - +) -> ProjectAndUnifyResult<'tcx> { let mut obligations = vec![]; let infcx = selcx.infcx(); @@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>( &mut obligations, ) { Ok(Some(n)) => n, - Ok(None) => return Ok(Ok(None)), - Err(InProgress) => return Ok(Err(InProgress)), + Ok(None) => return ProjectAndUnifyResult::FailedNormalization, + Err(InProgress) => return ProjectAndUnifyResult::Recursive, }; debug!(?normalized, ?obligations, "project_and_unify_type result"); match infcx @@ -220,11 +256,11 @@ fn project_and_unify_type<'cx, 'tcx>( { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); - Ok(Ok(Some(obligations))) + ProjectAndUnifyResult::Holds(obligations) } Err(err) => { - debug!("project_and_unify_type: equating types encountered error {:?}", err); - Err(MismatchedProjectionTypes { err }) + debug!("equating types encountered error {:?}", err); + ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err }) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 72d156067a1dd..3f0e5b285a152 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -21,6 +21,7 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -524,7 +525,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let data = bound_predicate.rebind(data); let project_obligation = obligation.with(data); match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Ok(Some(mut subobligations))) => { + ProjectAndUnifyResult::Holds(mut subobligations) => { 'compute_res: { // If we've previously marked this projection as 'complete', then // use the final cached result (either `EvaluatedToOk` or @@ -572,9 +573,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { res } } - Ok(Ok(None)) => Ok(EvaluatedToAmbig), - Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur), - Err(_) => Ok(EvaluatedToErr), + ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), + ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur), + ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), } } diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs new file mode 100644 index 0000000000000..258b8cd35c777 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs @@ -0,0 +1,6 @@ +#![feature(generic_associated_types)] + +// This feature doesn't *currently* fire on any specific code; it's just a +// behavior change. Future changes might. +#[rustc_error] //~ the +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr new file mode 100644 index 0000000000000..6a5eba38cacc6 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr @@ -0,0 +1,11 @@ +error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable + --> $DIR/feature-gate-generic_associated_types_extended.rs:5:1 + | +LL | #[rustc_error] + | ^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator.base.nll.stderr b/src/test/ui/generic-associated-types/extended/lending_iterator.base.nll.stderr new file mode 100644 index 0000000000000..3da7794b3d2c0 --- /dev/null +++ b/src/test/ui/generic-associated-types/extended/lending_iterator.base.nll.stderr @@ -0,0 +1,12 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/lending_iterator.rs:14:45 + | +LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; + | ------------------------------------------------------------------------ definition of `from_iter` from trait +... +LL | fn from_iter LendingIterator = A>>(mut iter: I) -> Self { + | ^^^^^^^^^^^^ impl has extra requirement `I: 'x` + +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/extended/lending_iterator.base.stderr b/src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr new file mode 100644 index 0000000000000..c5588b0912ba8 --- /dev/null +++ b/src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr @@ -0,0 +1,26 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/lending_iterator.rs:14:45 + | +LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; + | ------------------------------------------------------------------------ definition of `from_iter` from trait +... +LL | fn from_iter LendingIterator = A>>(mut iter: I) -> Self { + | ^^^^^^^^^^^^ impl has extra requirement `I: 'x` + +error[E0311]: the parameter type `Self` may not live long enough + --> $DIR/lending_iterator.rs:35:9 + | +LL | >::from_iter(self) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `Self: 'a`... + = note: ...so that the type `Self` will meet its required lifetime bounds... +note: ...that is required by this bound + --> $DIR/lending_iterator.rs:10:45 + | +LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator.rs b/src/test/ui/generic-associated-types/extended/lending_iterator.rs new file mode 100644 index 0000000000000..df11ab2124986 --- /dev/null +++ b/src/test/ui/generic-associated-types/extended/lending_iterator.rs @@ -0,0 +1,40 @@ +// revisions: base extended +//[base] check-fail +//[extended] check-pass + +#![feature(generic_associated_types)] +#![cfg_attr(extended, feature(generic_associated_types_extended))] +#![cfg_attr(extended, allow(incomplete_features))] + +pub trait FromLendingIterator: Sized { + fn from_iter LendingIterator = A>>(iter: T) -> Self; +} + +impl FromLendingIterator for Vec { + fn from_iter LendingIterator = A>>(mut iter: I) -> Self { + //[base]~^ impl has stricter + let mut v = vec![]; + while let Some(item) = iter.next() { + v.push(item); + } + v + } +} + +pub trait LendingIterator { + type Item<'z> + where + Self: 'z; + fn next(&mut self) -> Option>; + + fn collect>(self) -> B + where + Self: Sized, + Self: for<'q> LendingIterator = A>, + { + >::from_iter(self) + //[base]~^ the parameter type + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr b/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr new file mode 100644 index 0000000000000..6c2a624ca11d5 --- /dev/null +++ b/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr @@ -0,0 +1,12 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/lending_iterator_2.rs:14:45 + | +LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; + | ------------------------------------------------------------------------ definition of `from_iter` from trait +... +LL | fn from_iter LendingIterator = A>>(mut iter: I) -> Self { + | ^^^^^^^^^^^^ impl has extra requirement `I: 'x` + +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/extended/lending_iterator_2.rs b/src/test/ui/generic-associated-types/extended/lending_iterator_2.rs new file mode 100644 index 0000000000000..3c4a2184db90c --- /dev/null +++ b/src/test/ui/generic-associated-types/extended/lending_iterator_2.rs @@ -0,0 +1,31 @@ +// revisions: base extended +//[base] check-fail +//[extended] check-pass + +#![feature(generic_associated_types)] +#![cfg_attr(extended, feature(generic_associated_types_extended))] +#![cfg_attr(extended, allow(incomplete_features))] + +pub trait FromLendingIterator: Sized { + fn from_iter LendingIterator = A>>(iter: T) -> Self; +} + +impl FromLendingIterator for Vec { + fn from_iter LendingIterator = A>>(mut iter: I) -> Self { + //[base]~^ impl has stricter + let mut v = vec![]; + while let Some(item) = iter.next() { + v.push(item); + } + v + } +} + +pub trait LendingIterator { + type Item<'a> + where + Self: 'a; + fn next(&mut self) -> Option>; +} + +fn main() {}