diff --git a/.gitmodules b/.gitmodules index 6b2714edd4d12..4a136cff1cdf2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -65,3 +65,6 @@ [submodule "src/doc/rustc-guide"] path = src/doc/rustc-guide url = https://github.com/rust-lang/rustc-guide.git +[submodule "src/doc/edition-guide"] + path = src/doc/edition-guide + url = https://github.com/rust-lang-nursery/edition-guide diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f9b19ffb10d69..18a2b950e5966 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -70,6 +70,7 @@ macro_rules! book { book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; + EditionGuide, "src/doc/edition-guide", "edition-guide"; RustdocBook, "src/doc/rustdoc", "rustdoc"; RustcBook, "src/doc/rustc", "rustc"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; diff --git a/src/doc/edition-guide b/src/doc/edition-guide new file mode 160000 index 0000000000000..ad895867b6751 --- /dev/null +++ b/src/doc/edition-guide @@ -0,0 +1 @@ +Subproject commit ad895867b675199a7f597ce7045a56875a7e516a diff --git a/src/doc/nomicon b/src/doc/nomicon index f8a4e96feb2e5..b7eb4a087207a 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit f8a4e96feb2e5a6ed1ef170ad40e3509a7755cb4 +Subproject commit b7eb4a087207af2405c0669fa577f8545b894c66 diff --git a/src/doc/unstable-book/src/language-features/self-struct-ctor.md b/src/doc/unstable-book/src/language-features/self-struct-ctor.md deleted file mode 100644 index b4742c48a32ff..0000000000000 --- a/src/doc/unstable-book/src/language-features/self-struct-ctor.md +++ /dev/null @@ -1,33 +0,0 @@ -# `self_struct_ctor` - -The tracking issue for this feature is: [#51994] -[#51994]: https://github.com/rust-lang/rust/issues/51994 - ------------------------- - -The `self_struct_ctor` feature gate lets you use the special `Self` -identifier as a constructor and a pattern. - -A simple example is: - -```rust -#![feature(self_struct_ctor)] - -struct ST(i32, i32); - -impl ST { - fn new() -> Self { - ST(0, 1) - } - - fn ctor() -> Self { - Self(1,2) // constructed by `Self`, it is the same as `ST(1, 2)` - } - - fn pattern(self) { - match self { - Self(x, y) => println!("{} {}", x, y), // used as a pattern - } - } -} -``` diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 8d009101ce7da..0b25d911a299c 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -618,6 +618,8 @@ impl String { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf16(v: &[u16]) -> Result { + // This isn't done via collect::>() for performance reasons. + // FIXME: the function can be simplified again when #48994 is closed. let mut ret = String::with_capacity(v.len()); for c in decode_utf16(v.iter().cloned()) { if let Ok(c) = c { diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index dae05a368fa06..955cab1d93f76 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -298,6 +298,7 @@ pub struct DroplessArena { unsafe impl Send for DroplessArena {} impl Default for DroplessArena { + #[inline] fn default() -> DroplessArena { DroplessArena { ptr: Cell::new(0 as *mut u8), @@ -319,6 +320,7 @@ impl DroplessArena { false } + #[inline] fn align(&self, align: usize) { let final_address = ((self.ptr.get() as usize) + align - 1) & !(align - 1); self.ptr.set(final_address as *mut u8); diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 0b01cfc488bba..7fd61f07d5e7f 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -21,3 +21,7 @@ path = "../libcore/benches/lib.rs" [dev-dependencies] rand = "0.5" + +[features] +# Make panics and failed asserts immediately abort without formatting any message +panic_immediate_abort = [] diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d24f8902bd83..26e7a79d35df6 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -148,6 +148,15 @@ macro_rules! array_impls { } } + #[unstable(feature = "try_from", issue = "33417")] + impl<'a, T> TryFrom<&'a [T]> for [T; $N] where T: Copy { + type Error = TryFromSliceError; + + fn try_from(slice: &[T]) -> Result<[T; $N], TryFromSliceError> { + <&Self>::try_from(slice).map(|r| *r) + } + } + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 57b5903c9d39f..805be431328e2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1989,6 +1989,19 @@ big endian. ``` let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +#![feature(try_from)] +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -2008,6 +2021,19 @@ little endian. ``` let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +#![feature(try_from)] +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -2037,6 +2063,19 @@ let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"bi ", $le_bytes, " }); assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +#![feature(try_from)] +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -3614,6 +3653,7 @@ assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); assert_eq!(", stringify!($SelfT), "::max_value().checked_next_power_of_two(), None);", $EndFeature, " ```"), + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn checked_next_power_of_two(self) -> Option { self.one_less_than_next_power_of_two().checked_add(1) @@ -3719,6 +3759,19 @@ big endian. ``` let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +#![feature(try_from)] +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -3738,6 +3791,19 @@ little endian. ``` let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +#![feature(try_from)] +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] @@ -3767,6 +3833,19 @@ let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"bi ", $le_bytes, " }); assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +#![feature(try_from)] +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 58407de9566e9..aa18a60fc0f6d 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -39,9 +39,16 @@ use fmt; use panic::{Location, PanicInfo}; -#[cold] #[inline(never)] // this is the slow path, always +#[cold] +// never inline unless panic_immediate_abort to avoid code +// bloat at the call sites as much as possible +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[lang = "panic"] pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { super::intrinsics::abort() } + } + // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially // reduce size overhead. The format_args! macro uses str's Display trait to // write expr, which calls Formatter::pad, which must accommodate string @@ -52,16 +59,27 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col)) } -#[cold] #[inline(never)] +#[cold] +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[lang = "panic_bounds_check"] fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), index: usize, len: usize) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { super::intrinsics::abort() } + } + panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", len, index), file_line_col) } -#[cold] #[inline(never)] +#[cold] +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] +#[cfg_attr( feature="panic_immediate_abort" ,inline)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { super::intrinsics::abort() } + } + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe extern "Rust" { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b3ba2968c9f51..dc8baa112bb59 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -67,7 +67,6 @@ use syntax::ast; use syntax::ast::*; use syntax::errors; use syntax::ext::hygiene::{Mark, SyntaxContext}; -use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::print::pprust; use syntax::ptr::P; use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned}; @@ -3628,7 +3627,6 @@ impl<'a> LoweringContext<'a> { ParamMode::Optional, ImplTraitContext::disallowed(), ); - self.check_self_struct_ctor_feature(&qpath); hir::PatKind::TupleStruct( qpath, pats.iter().map(|x| self.lower_pat(x)).collect(), @@ -3643,7 +3641,6 @@ impl<'a> LoweringContext<'a> { ParamMode::Optional, ImplTraitContext::disallowed(), ); - self.check_self_struct_ctor_feature(&qpath); hir::PatKind::Path(qpath) } PatKind::Struct(ref path, ref fields, etc) => { @@ -4039,7 +4036,6 @@ impl<'a> LoweringContext<'a> { ParamMode::Optional, ImplTraitContext::disallowed(), ); - self.check_self_struct_ctor_feature(&qpath); hir::ExprKind::Path(qpath) } ExprKind::Break(opt_label, ref opt_expr) => { @@ -5102,18 +5098,6 @@ impl<'a> LoweringContext<'a> { ThinVec::new())); P(self.expr_call(e.span, from_err, hir_vec![e])) } - - fn check_self_struct_ctor_feature(&self, qp: &hir::QPath) { - if let hir::QPath::Resolved(_, ref p) = qp { - if p.segments.len() == 1 && - p.segments[0].ident.name == keywords::SelfType.name() && - !self.sess.features_untracked().self_struct_ctor { - emit_feature_err(&self.sess.parse_sess, "self_struct_ctor", - p.span, GateIssue::Language, - "`Self` struct constructors are unstable"); - } - } - } } fn body_ids(bodies: &BTreeMap) -> Vec { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index e69d32ad1deaf..9a0ceddcf1b4a 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -25,6 +25,7 @@ use hir; use hir::{PatKind, GenericBound, TraitBoundModifier, RangeEnd}; use hir::{GenericParam, GenericParamKind, GenericArg}; +use std::borrow::Cow; use std::cell::Cell; use std::io::{self, Write, Read}; use std::iter::Peekable; @@ -209,7 +210,7 @@ pub fn to_string(ann: &dyn PpAnn, f: F) -> String String::from_utf8(wr).unwrap() } -pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String { +pub fn visibility_qualified>>(vis: &hir::Visibility, w: S) -> String { to_string(NO_ANN, |s| { s.print_visibility(vis)?; s.s.word(w) @@ -226,12 +227,13 @@ impl<'a> State<'a> { self.s.word(" ") } - pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> { + pub fn word_nbsp>>(&mut self, w: S) -> io::Result<()> { self.s.word(w)?; self.nbsp() } - pub fn head(&mut self, w: &str) -> io::Result<()> { + pub fn head>>(&mut self, w: S) -> io::Result<()> { + let w = w.into(); // outer-box is consistent self.cbox(indent_unit)?; // head-box is inconsistent @@ -303,7 +305,7 @@ impl<'a> State<'a> { pub fn synth_comment(&mut self, text: String) -> io::Result<()> { self.s.word("/*")?; self.s.space()?; - self.s.word(&text[..])?; + self.s.word(text)?; self.s.space()?; self.s.word("*/") } @@ -468,7 +470,7 @@ impl<'a> State<'a> { self.end() // end the outer fn box } hir::ForeignItemKind::Static(ref t, m) => { - self.head(&visibility_qualified(&item.vis, "static"))?; + self.head(visibility_qualified(&item.vis, "static"))?; if m { self.word_space("mut")?; } @@ -480,7 +482,7 @@ impl<'a> State<'a> { self.end() // end the outer cbox } hir::ForeignItemKind::Type => { - self.head(&visibility_qualified(&item.vis, "type"))?; + self.head(visibility_qualified(&item.vis, "type"))?; self.print_name(item.name)?; self.s.word(";")?; self.end()?; // end the head-ibox @@ -495,7 +497,7 @@ impl<'a> State<'a> { default: Option, vis: &hir::Visibility) -> io::Result<()> { - self.s.word(&visibility_qualified(vis, ""))?; + self.s.word(visibility_qualified(vis, ""))?; self.word_space("const")?; self.print_ident(ident)?; self.word_space(":")?; @@ -534,7 +536,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Item(item))?; match item.node { hir::ItemKind::ExternCrate(orig_name) => { - self.head(&visibility_qualified(&item.vis, "extern crate"))?; + self.head(visibility_qualified(&item.vis, "extern crate"))?; if let Some(orig_name) = orig_name { self.print_name(orig_name)?; self.s.space()?; @@ -547,7 +549,7 @@ impl<'a> State<'a> { self.end()?; // end outer head-block } hir::ItemKind::Use(ref path, kind) => { - self.head(&visibility_qualified(&item.vis, "use"))?; + self.head(visibility_qualified(&item.vis, "use"))?; self.print_path(path, false)?; match kind { @@ -566,7 +568,7 @@ impl<'a> State<'a> { self.end()?; // end outer head-block } hir::ItemKind::Static(ref ty, m, expr) => { - self.head(&visibility_qualified(&item.vis, "static"))?; + self.head(visibility_qualified(&item.vis, "static"))?; if m == hir::MutMutable { self.word_space("mut")?; } @@ -582,7 +584,7 @@ impl<'a> State<'a> { self.end()?; // end the outer cbox } hir::ItemKind::Const(ref ty, expr) => { - self.head(&visibility_qualified(&item.vis, "const"))?; + self.head(visibility_qualified(&item.vis, "const"))?; self.print_name(item.name)?; self.word_space(":")?; self.print_type(&ty)?; @@ -609,7 +611,7 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(body))?; } hir::ItemKind::Mod(ref _mod) => { - self.head(&visibility_qualified(&item.vis, "mod"))?; + self.head(visibility_qualified(&item.vis, "mod"))?; self.print_name(item.name)?; self.nbsp()?; self.bopen()?; @@ -618,18 +620,18 @@ impl<'a> State<'a> { } hir::ItemKind::ForeignMod(ref nmod) => { self.head("extern")?; - self.word_nbsp(&nmod.abi.to_string())?; + self.word_nbsp(nmod.abi.to_string())?; self.bopen()?; self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } hir::ItemKind::GlobalAsm(ref ga) => { - self.head(&visibility_qualified(&item.vis, "global asm"))?; - self.s.word(&ga.asm.as_str())?; + self.head(visibility_qualified(&item.vis, "global asm"))?; + self.s.word(ga.asm.as_str().get())?; self.end()? } hir::ItemKind::Ty(ref ty, ref generics) => { - self.head(&visibility_qualified(&item.vis, "type"))?; + self.head(visibility_qualified(&item.vis, "type"))?; self.print_name(item.name)?; self.print_generic_params(&generics.params)?; self.end()?; // end the inner ibox @@ -642,7 +644,7 @@ impl<'a> State<'a> { self.end()?; // end the outer ibox } hir::ItemKind::Existential(ref exist) => { - self.head(&visibility_qualified(&item.vis, "existential type"))?; + self.head(visibility_qualified(&item.vis, "existential type"))?; self.print_name(item.name)?; self.print_generic_params(&exist.generics.params)?; self.end()?; // end the inner ibox @@ -668,11 +670,11 @@ impl<'a> State<'a> { self.print_enum_def(enum_definition, params, item.name, item.span, &item.vis)?; } hir::ItemKind::Struct(ref struct_def, ref generics) => { - self.head(&visibility_qualified(&item.vis, "struct"))?; + self.head(visibility_qualified(&item.vis, "struct"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } hir::ItemKind::Union(ref struct_def, ref generics) => { - self.head(&visibility_qualified(&item.vis, "union"))?; + self.head(visibility_qualified(&item.vis, "union"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } hir::ItemKind::Impl(unsafety, @@ -795,7 +797,7 @@ impl<'a> State<'a> { span: syntax_pos::Span, visibility: &hir::Visibility) -> io::Result<()> { - self.head(&visibility_qualified(visibility, "enum"))?; + self.head(visibility_qualified(visibility, "enum"))?; self.print_name(name)?; self.print_generic_params(&generics.params)?; self.print_where_clause(&generics.where_clause)?; @@ -1587,14 +1589,14 @@ impl<'a> State<'a> { } pub fn print_usize(&mut self, i: usize) -> io::Result<()> { - self.s.word(&i.to_string()) + self.s.word(i.to_string()) } pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> { if ident.is_raw_guess() { - self.s.word(&format!("r#{}", ident.name))?; + self.s.word(format!("r#{}", ident.name))?; } else { - self.s.word(&ident.as_str())?; + self.s.word(ident.as_str().get())?; } self.ann.post(self, AnnNode::Name(&ident.name)) } @@ -2010,7 +2012,7 @@ impl<'a> State<'a> { self.commasep(Inconsistent, &decl.inputs, |s, ty| { s.ibox(indent_unit)?; if let Some(arg_name) = arg_names.get(i) { - s.s.word(&arg_name.as_str())?; + s.s.word(arg_name.as_str().get())?; s.s.word(":")?; s.s.space()?; } else if let Some(body_id) = body_id { @@ -2073,7 +2075,8 @@ impl<'a> State<'a> { } } - pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::GenericBound]) -> io::Result<()> { + pub fn print_bounds(&mut self, prefix: &'static str, bounds: &[hir::GenericBound]) + -> io::Result<()> { if !bounds.is_empty() { self.s.word(prefix)?; let mut first = true; @@ -2322,7 +2325,7 @@ impl<'a> State<'a> { Some(Abi::Rust) => Ok(()), Some(abi) => { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string()) + self.word_nbsp(abi.to_string()) } None => Ok(()), } @@ -2332,7 +2335,7 @@ impl<'a> State<'a> { match opt_abi { Some(abi) => { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string()) + self.word_nbsp(abi.to_string()) } None => Ok(()), } @@ -2342,7 +2345,7 @@ impl<'a> State<'a> { header: hir::FnHeader, vis: &hir::Visibility) -> io::Result<()> { - self.s.word(&visibility_qualified(vis, ""))?; + self.s.word(visibility_qualified(vis, ""))?; match header.constness { hir::Constness::NotConst => {} @@ -2358,7 +2361,7 @@ impl<'a> State<'a> { if header.abi != Abi::Rust { self.word_nbsp("extern")?; - self.word_nbsp(&header.abi.to_string())?; + self.word_nbsp(header.abi.to_string())?; } self.s.word("fn") diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index 0e4c94aaaf394..70e922c6676e1 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -52,6 +52,7 @@ pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + #[inline] pub fn at(&'a self, cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>) diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 9bdbf77fee0a9..972ba16f7e2c7 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -11,30 +11,41 @@ //! This code is kind of an alternate way of doing subtyping, //! supertyping, and type equating, distinct from the `combine.rs` //! code but very similar in its effect and design. Eventually the two -//! ought to be merged. This code is intended for use in NLL. +//! ought to be merged. This code is intended for use in NLL and chalk. //! //! Here are the key differences: //! -//! - This code generally assumes that there are no unbound type -//! inferences variables, because at NLL -//! time types are fully inferred up-to regions. -//! - Actually, to support user-given type annotations like -//! `Vec<_>`, we do have some measure of support for type -//! inference variables, but we impose some simplifying -//! assumptions on them that would not be suitable for the infer -//! code more generally. This could be fixed. +//! - This code may choose to bypass some checks (e.g. the occurs check) +//! in the case where we know that there are no unbound type inference +//! variables. This is the case for NLL, because at NLL time types are fully +//! inferred up-to regions. //! - This code uses "universes" to handle higher-ranked regions and //! not the leak-check. This is "more correct" than what rustc does //! and we are generally migrating in this direction, but NLL had to //! get there first. +//! +//! Also, this code assumes that there are no bound types at all, not even +//! free ones. This is ok because: +//! - we are not relating anything quantified over some type variable +//! - we will have instantiated all the bound type vars already (the one +//! thing we relate in chalk are basically domain goals and their +//! constituents) use crate::infer::InferCtxt; use crate::ty::fold::{TypeFoldable, TypeVisitor}; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::Kind; use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::error::TypeError; +use crate::traits::DomainGoal; use rustc_data_structures::fx::FxHashMap; +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum NormalizationStrategy { + Lazy, + Eager, +} + pub struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D> where D: TypeRelatingDelegate<'tcx>, @@ -75,6 +86,10 @@ pub trait TypeRelatingDelegate<'tcx> { /// delegate. fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); + /// Push a domain goal that will need to be proved for the two types to + /// be related. Used for lazy normalization. + fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>); + /// Creates a new universe index. Used when instantiating placeholders. fn create_next_universe(&mut self) -> ty::UniverseIndex; @@ -105,6 +120,13 @@ pub trait TypeRelatingDelegate<'tcx> { /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives /// relation stating that `'?0: 'a`). fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; + + /// Define the normalization strategy to use, eager or lazy. + fn normalization() -> NormalizationStrategy; + + /// Enable some optimizations if we do not expect inference variables + /// in the RHS of the relation. + fn forbid_inference_vars() -> bool; } #[derive(Clone, Debug)] @@ -242,15 +264,79 @@ where self.delegate.push_outlives(sup, sub); } - /// When we encounter a canonical variable `var` in the output, - /// equate it with `kind`. If the variable has been previously - /// equated, then equate it again. - fn relate_var(&mut self, var_ty: Ty<'tcx>, value_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty); + /// Relate a projection type and some value type lazily. This will always + /// succeed, but we push an additional `ProjectionEq` goal depending + /// on the value type: + /// - if the value type is any type `T` which is not a projection, we push + /// `ProjectionEq(projection = T)`. + /// - if the value type is another projection `other_projection`, we create + /// a new inference variable `?U` and push the two goals + /// `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`. + fn relate_projection_ty( + &mut self, + projection_ty: ty::ProjectionTy<'tcx>, + value_ty: ty::Ty<'tcx> + ) -> Ty<'tcx> { + use crate::infer::type_variable::TypeVariableOrigin; + use crate::traits::WhereClause; + use syntax_pos::DUMMY_SP; + + match value_ty.sty { + ty::Projection(other_projection_ty) => { + let var = self.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); + self.relate_projection_ty(projection_ty, var); + self.relate_projection_ty(other_projection_ty, var); + var + } + + _ => { + let projection = ty::ProjectionPredicate { + projection_ty, + ty: value_ty, + }; + self.delegate.push_domain_goal( + DomainGoal::Holds(WhereClause::ProjectionEq(projection)) + ); + value_ty + } + } + } + + /// Relate a type inference variable with a value type. + fn relate_ty_var( + &mut self, + vid: ty::TyVid, + value_ty: Ty<'tcx> + ) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("relate_ty_var(vid={:?}, value_ty={:?})", vid, value_ty); + + match value_ty.sty { + ty::Infer(ty::TyVar(value_vid)) => { + // Two type variables: just equate them. + self.infcx.type_variables.borrow_mut().equate(vid, value_vid); + return Ok(value_ty); + } + + ty::Projection(projection_ty) + if D::normalization() == NormalizationStrategy::Lazy => + { + return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_var(vid))); + } + + _ => (), + } + + let generalized_ty = self.generalize_value(value_ty, vid)?; + debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); + + if D::forbid_inference_vars() { + // In NLL, we don't have type inference variables + // floating around, so we can do this rather imprecise + // variant of the occurs-check. + assert!(!generalized_ty.has_infer_types()); + } - let generalized_ty = self.generalize_value(value_ty); - self.infcx - .force_instantiate_unchecked(var_ty, generalized_ty); + self.infcx.type_variables.borrow_mut().instantiate(vid, generalized_ty); // The generalized values we extract from `canonical_var_values` have // been fully instantiated and hence the set of scopes we have @@ -264,22 +350,27 @@ where // Restore the old scopes now. self.a_scopes = old_a_scopes; - debug!("equate_var: complete, result = {:?}", result); + debug!("relate_ty_var: complete, result = {:?}", result); result } - fn generalize_value>(&mut self, value: T) -> T { - TypeGeneralizer { - tcx: self.infcx.tcx, + fn generalize_value>( + &mut self, + value: T, + for_vid: ty::TyVid + ) -> RelateResult<'tcx, T> { + let universe = self.infcx.probe_ty_var(for_vid).unwrap_err(); + + let mut generalizer = TypeGeneralizer { + infcx: self.infcx, delegate: &mut self.delegate, first_free_index: ty::INNERMOST, ambient_variance: self.ambient_variance, + for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), + universe, + }; - // These always correspond to an `_` or `'_` written by - // user, and those are always in the root universe. - universe: ty::UniverseIndex::ROOT, - }.relate(&value, &value) - .unwrap() + generalizer.relate(&value, &value) } } @@ -327,11 +418,35 @@ where Ok(r) } - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let a = self.infcx.shallow_resolve(a); - match a.sty { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { - self.relate_var(a.into(), b.into()) + + if !D::forbid_inference_vars() { + b = self.infcx.shallow_resolve(b); + } + + match (&a.sty, &b.sty) { + (_, &ty::Infer(ty::TyVar(vid))) => { + if D::forbid_inference_vars() { + // Forbid inference variables in the RHS. + bug!("unexpected inference var {:?}", b) + } else { + self.relate_ty_var(vid, a) + } + } + + (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var(vid, b), + + (&ty::Projection(projection_ty), _) + if D::normalization() == NormalizationStrategy::Lazy => + { + Ok(self.relate_projection_ty(projection_ty, b)) + } + + (_, &ty::Projection(projection_ty)) + if D::normalization() == NormalizationStrategy::Lazy => + { + Ok(self.relate_projection_ty(projection_ty, a)) } _ => { @@ -340,7 +455,8 @@ where a, b, self.ambient_variance ); - relate::super_relate_tys(self, a, b) + // Will also handle unification of `IntVar` and `FloatVar`. + self.infcx.super_combine_tys(self, a, b) } } } @@ -551,7 +667,7 @@ struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D> where D: TypeRelatingDelegate<'tcx> + 'me, { - tcx: TyCtxt<'me, 'gcx, 'tcx>, + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, delegate: &'me mut D, @@ -561,6 +677,14 @@ where first_free_index: ty::DebruijnIndex, + /// The vid of the type variable that is in the process of being + /// instantiated. If we find this within the value we are folding, + /// that means we would have created a cyclic value. + for_vid_sub_root: ty::TyVid, + + /// The universe of the type variable that is in the process of being + /// instantiated. If we find anything that this universe cannot name, + /// we reject the relation. universe: ty::UniverseIndex, } @@ -569,7 +693,7 @@ where D: TypeRelatingDelegate<'tcx>, { fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { - self.tcx + self.infcx.tcx } fn tag(&self) -> &'static str { @@ -609,17 +733,84 @@ where } fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + use crate::infer::type_variable::TypeVariableValue; + debug!("TypeGeneralizer::tys(a={:?})", a,); match a.sty { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { + ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) + if D::forbid_inference_vars() => + { bug!( "unexpected inference variable encountered in NLL generalization: {:?}", a ); } - _ => relate::super_relate_tys(self, a, a), + ty::Infer(ty::TyVar(vid)) => { + let mut variables = self.infcx.type_variables.borrow_mut(); + let vid = variables.root_var(vid); + let sub_vid = variables.sub_root_var(vid); + if sub_vid == self.for_vid_sub_root { + // If sub-roots are equal, then `for_vid` and + // `vid` are related via subtyping. + debug!("TypeGeneralizer::tys: occurs check failed"); + return Err(TypeError::Mismatch); + } else { + match variables.probe(vid) { + TypeVariableValue::Known { value: u } => { + drop(variables); + self.relate(&u, &u) + } + TypeVariableValue::Unknown { universe: _universe } => { + if self.ambient_variance == ty::Bivariant { + // FIXME: we may need a WF predicate (related to #54105). + } + + let origin = *variables.var_origin(vid); + + // Replacing with a new variable in the universe `self.universe`, + // it will be unified later with the original type variable in + // the universe `_universe`. + let new_var_id = variables.new_var(self.universe, false, origin); + + let u = self.tcx().mk_var(new_var_id); + debug!( + "generalize: replacing original vid={:?} with new={:?}", + vid, + u + ); + return Ok(u); + } + } + } + } + + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) => { + // No matter what mode we are in, + // integer/floating-point types must be equal to be + // relatable. + Ok(a) + } + + ty::Placeholder(placeholder) => { + if self.universe.cannot_name(placeholder.universe) { + debug!( + "TypeGeneralizer::tys: root universe {:?} cannot name\ + placeholder in universe {:?}", + self.universe, + placeholder.universe + ); + Err(TypeError::Mismatch) + } else { + Ok(a) + } + } + + _ => { + relate::super_relate_tys(self, a, a) + } } } @@ -673,64 +864,3 @@ where Ok(ty::Binder::bind(result)) } } - -impl InferCtxt<'_, '_, 'tcx> { - /// A hacky sort of method used by the NLL type-relating code: - /// - /// - `var` must be some unbound type variable. - /// - `value` must be a suitable type to use as its value. - /// - /// `var` will then be equated with `value`. Note that this - /// sidesteps a number of important checks, such as the "occurs - /// check" that prevents cyclic types, so it is important not to - /// use this method during regular type-check. - fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) { - match (&var.sty, &value.sty) { - (&ty::Infer(ty::TyVar(vid)), _) => { - let mut type_variables = self.type_variables.borrow_mut(); - - // In NLL, we don't have type inference variables - // floating around, so we can do this rather imprecise - // variant of the occurs-check. - assert!(!value.has_infer_types()); - - type_variables.instantiate(vid, value); - } - - (&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => { - let mut int_unification_table = self.int_unification_table.borrow_mut(); - int_unification_table - .unify_var_value(vid, Some(ty::IntVarValue::IntType(value))) - .unwrap_or_else(|_| { - bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); - }); - } - - (&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => { - let mut int_unification_table = self.int_unification_table.borrow_mut(); - int_unification_table - .unify_var_value(vid, Some(ty::IntVarValue::UintType(value))) - .unwrap_or_else(|_| { - bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); - }); - } - - (&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => { - let mut float_unification_table = self.float_unification_table.borrow_mut(); - float_unification_table - .unify_var_value(vid, Some(ty::FloatVarValue(value))) - .unwrap_or_else(|_| { - bug!("failed to unify float var `{:?}` with `{:?}`", vid, value) - }); - } - - _ => { - bug!( - "force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}", - var, - value, - ); - } - } - } -} diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index a0c310ac2761e..7a1ee85acd42c 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -25,6 +25,7 @@ pub struct OpportunisticTypeResolver<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> OpportunisticTypeResolver<'a, 'gcx, 'tcx> { + #[inline] pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { OpportunisticTypeResolver { infcx } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0009a517dd1db..ab0094df0e219 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -117,8 +117,9 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { self.reachable_symbols.insert(node_id); } Some(def) => { - let def_id = def.def_id(); - if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { + if let Some((node_id, def_id)) = def.opt_def_id().and_then(|def_id| { + self.tcx.hir.as_local_node_id(def_id).map(|node_id| (node_id, def_id)) + }) { if self.def_id_represents_local_inlined_item(def_id) { self.worklist.push(node_id); } else { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 6ff450508d136..07054ee99af76 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1573,7 +1573,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .collect(); // ensure that we issue lints in a repeatable order - def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id)); + def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); for def_id in def_ids { debug!( diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 3fd22793a08a0..480d4a8e48f0e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1286,8 +1286,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print some performance-related statistics"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR"), - mir_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about MIR"), always_encode_mir: bool = (false, parse_bool, [TRACKED], "encode MIR of all functions into the crate metadata"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e582a9020464d..ab2fa68ab5f89 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -1052,6 +1052,7 @@ impl<'tcx,O> Obligation<'tcx,O> { } impl<'tcx> ObligationCause<'tcx> { + #[inline] pub fn new(span: Span, body_id: ast::NodeId, code: ObligationCauseCode<'tcx>) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c79fa3861234f..2909daf22b3ba 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { .collect::>(); // existential predicates need to be in a specific order - associated_types.sort_by_key(|item| self.def_path_hash(item.def_id)); + associated_types.sort_by_cached_key(|item| self.def_path_hash(item.def_id)); let projection_predicates = associated_types.into_iter().map(|item| { ty::ExistentialPredicate::Projection(ty::ExistentialProjection { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 79a4638d6f7d9..42a4de1682c39 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -53,6 +53,7 @@ use ty::CanonicalTy; use ty::CanonicalPolyFnSig; use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; +use rustc_data_structures::interner::HashInterner; use smallvec::SmallVec; use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, @@ -113,7 +114,7 @@ pub struct GlobalArenas<'tcx> { const_allocs: TypedArena, } -type InternedSet<'tcx, T> = Lock>>; +type InternedSet<'tcx, T> = Lock, ()>>; pub struct CtxtInterners<'tcx> { /// The arena that types, regions, etc are allocated from @@ -155,6 +156,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { } /// Intern a type + #[inline(never)] fn intern_ty( local: &CtxtInterners<'tcx>, global: &CtxtInterners<'gcx>, @@ -166,56 +168,45 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { // determine that all contents are in the global tcx. // See comments on Lift for why we can't use that. if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { - let mut interner = local.type_.borrow_mut(); - if let Some(&Interned(ty)) = interner.get(&st) { - return ty; - } - - let ty_struct = TyS { - sty: st, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; + local.type_.borrow_mut().intern(st, |st| { + let ty_struct = TyS { + sty: st, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; - // Make sure we don't end up with inference - // types/regions in the global interner - if local as *const _ as usize == global as *const _ as usize { - bug!("Attempted to intern `{:?}` which contains \ - inference types/regions in the global type context", - &ty_struct); - } + // Make sure we don't end up with inference + // types/regions in the global interner + if local as *const _ as usize == global as *const _ as usize { + bug!("Attempted to intern `{:?}` which contains \ + inference types/regions in the global type context", + &ty_struct); + } - // Don't be &mut TyS. - let ty: Ty<'tcx> = local.arena.alloc(ty_struct); - interner.insert(Interned(ty)); - ty + Interned(local.arena.alloc(ty_struct)) + }).0 } else { - let mut interner = global.type_.borrow_mut(); - if let Some(&Interned(ty)) = interner.get(&st) { - return ty; - } - - let ty_struct = TyS { - sty: st, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; + global.type_.borrow_mut().intern(st, |st| { + let ty_struct = TyS { + sty: st, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; - // This is safe because all the types the ty_struct can point to - // already is in the global arena - let ty_struct: TyS<'gcx> = unsafe { - mem::transmute(ty_struct) - }; + // This is safe because all the types the ty_struct can point to + // already is in the global arena + let ty_struct: TyS<'gcx> = unsafe { + mem::transmute(ty_struct) + }; - // Don't be &mut TyS. - let ty: Ty<'gcx> = global.arena.alloc(ty_struct); - interner.insert(Interned(ty)); - ty + Interned(global.arena.alloc(ty_struct)) + }).0 } } } pub struct CommonTypes<'tcx> { + pub unit: Ty<'tcx>, pub bool: Ty<'tcx>, pub char: Ty<'tcx>, pub isize: Ty<'tcx>, @@ -825,14 +816,13 @@ impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty); let mk_region = |r| { - if let Some(r) = interners.region.borrow().get(&r) { - return r.0; - } - let r = interners.arena.alloc(r); - interners.region.borrow_mut().insert(Interned(r)); - &*r + interners.region.borrow_mut().intern(r, |r| { + Interned(interners.arena.alloc(r)) + }).0 }; + CommonTypes { + unit: mk(Tuple(List::empty())), bool: mk(Bool), char: mk(Char), never: mk(Never), @@ -885,6 +875,7 @@ pub struct TyCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> { type Target = &'a GlobalCtxt<'gcx>; + #[inline(always)] fn deref(&self) -> &Self::Target { &self.gcx } @@ -950,14 +941,14 @@ pub struct GlobalCtxt<'tcx> { /// Data layout specification for the current target. pub data_layout: TargetDataLayout, - stability_interner: Lock>, + stability_interner: Lock>, /// Stores the value of constants (and deduplicates the actual memory) - allocation_interner: Lock>, + allocation_interner: Lock>, pub alloc_map: Lock>, - layout_interner: Lock>, + layout_interner: Lock>, /// A general purpose channel to throw data out the back towards LLVM worker /// threads. @@ -1040,16 +1031,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self, alloc: Allocation, ) -> &'gcx Allocation { - let allocs = &mut self.allocation_interner.borrow_mut(); - if let Some(alloc) = allocs.get(&alloc) { - return alloc; - } - - let interned = self.global_arenas.const_allocs.alloc(alloc); - if let Some(prev) = allocs.replace(interned) { // insert into interner - bug!("Tried to overwrite interned Allocation: {:#?}", prev) - } - interned + self.allocation_interner.borrow_mut().intern(alloc, |alloc| { + self.global_arenas.const_allocs.alloc(alloc) + }) } /// Allocates a byte or string literal for `mir::interpret`, read-only @@ -1061,29 +1045,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability { - let mut stability_interner = self.stability_interner.borrow_mut(); - if let Some(st) = stability_interner.get(&stab) { - return st; - } - - let interned = self.global_interners.arena.alloc(stab); - if let Some(prev) = stability_interner.replace(interned) { - bug!("Tried to overwrite interned Stability: {:?}", prev) - } - interned + self.stability_interner.borrow_mut().intern(stab, |stab| { + self.global_interners.arena.alloc(stab) + }) } pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails { - let mut layout_interner = self.layout_interner.borrow_mut(); - if let Some(layout) = layout_interner.get(&layout) { - return layout; - } - - let interned = self.global_arenas.layout.alloc(layout); - if let Some(prev) = layout_interner.replace(interned) { - bug!("Tried to overwrite interned Layout: {:?}", prev) - } - interned + self.layout_interner.borrow_mut().intern(layout, |layout| { + self.global_arenas.layout.alloc(layout) + }) } /// Returns a range of the start/end indices specified with the @@ -2193,7 +2163,7 @@ macro_rules! sty_debug_print { }; $(let mut $variant = total;)* - for &Interned(t) in tcx.interners.type_.borrow().iter() { + for &Interned(t) in tcx.interners.type_.borrow().keys() { let variant = match t.sty { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, @@ -2252,6 +2222,13 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// An entry in an interner. struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T); +impl<'tcx, T: 'tcx+?Sized> Clone for Interned<'tcx, T> { + fn clone(&self) -> Self { + Interned(self.0) + } +} +impl<'tcx, T: 'tcx+?Sized> Copy for Interned<'tcx, T> {} + // NB: An Interned compares and hashes as a sty. impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { @@ -2372,37 +2349,28 @@ macro_rules! intern_method { // determine that all contents are in the global tcx. // See comments on Lift for why we can't use that. if ($keep_in_local_tcx)(&v) { - let mut interner = self.interners.$name.borrow_mut(); - if let Some(&Interned(v)) = interner.get(key) { - return v; - } - - // Make sure we don't end up with inference - // types/regions in the global tcx. - if self.is_global() { - bug!("Attempted to intern `{:?}` which contains \ - inference types/regions in the global type context", - v); - } - - let i = $alloc_method(&self.interners.arena, v); - interner.insert(Interned(i)); - i + self.interners.$name.borrow_mut().intern_ref(key, || { + // Make sure we don't end up with inference + // types/regions in the global tcx. + if self.is_global() { + bug!("Attempted to intern `{:?}` which contains \ + inference types/regions in the global type context", + v); + } + + Interned($alloc_method(&self.interners.arena, v)) + }).0 } else { - let mut interner = self.global_interners.$name.borrow_mut(); - if let Some(&Interned(v)) = interner.get(key) { - return v; - } - - // This transmutes $alloc<'tcx> to $alloc<'gcx> - let v = unsafe { - mem::transmute(v) - }; - let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v); - // Cast to 'gcx - let i = unsafe { mem::transmute(i) }; - interner.insert(Interned(i)); - i + self.global_interners.$name.borrow_mut().intern_ref(key, || { + // This transmutes $alloc<'tcx> to $alloc<'gcx> + let v = unsafe { + mem::transmute(v) + }; + let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v); + // Cast to 'gcx + let i = unsafe { mem::transmute(i) }; + Interned(i) + }).0 } } } @@ -2515,6 +2483,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_fn_ptr(converted_sig) } + #[inline] pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> { CtxtInterners::intern_ty(&self.interners, &self.global_interners, st) } @@ -2548,19 +2517,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + #[inline] pub fn mk_str(self) -> Ty<'tcx> { self.mk_ty(Str) } + #[inline] pub fn mk_static_str(self) -> Ty<'tcx> { self.mk_imm_ref(self.types.re_static, self.mk_str()) } + #[inline] pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside self.mk_ty(Adt(def, substs)) } + #[inline] pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> { self.mk_ty(Foreign(def_id)) } @@ -2584,42 +2557,52 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(Adt(adt_def, substs)) } + #[inline] pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { self.mk_ty(RawPtr(tm)) } + #[inline] pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { self.mk_ty(Ref(r, tm.ty, tm.mutbl)) } + #[inline] pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable}) } + #[inline] pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) } + #[inline] pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable}) } + #[inline] pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) } + #[inline] pub fn mk_nil_ptr(self) -> Ty<'tcx> { self.mk_imm_ptr(self.mk_unit()) } + #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { self.mk_ty(Array(ty, ty::Const::from_usize(self, n))) } + #[inline] pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ty(Slice(ty)) } + #[inline] pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { self.mk_ty(Tuple(self.intern_type_list(ts))) } @@ -2628,10 +2611,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { iter.intern_with(|ts| self.mk_ty(Tuple(self.intern_type_list(ts)))) } + #[inline] pub fn mk_unit(self) -> Ty<'tcx> { - self.intern_tup(&[]) + self.types.unit } + #[inline] pub fn mk_diverging_default(self) -> Ty<'tcx> { if self.features().never_type { self.types.never @@ -2640,19 +2625,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + #[inline] pub fn mk_bool(self) -> Ty<'tcx> { self.mk_ty(Bool) } + #[inline] pub fn mk_fn_def(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { self.mk_ty(FnDef(def_id, substs)) } + #[inline] pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { self.mk_ty(FnPtr(fty)) } + #[inline] pub fn mk_dynamic( self, obj: ty::Binder<&'tcx List>>, @@ -2661,6 +2650,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(Dynamic(obj, reg)) } + #[inline] pub fn mk_projection(self, item_def_id: DefId, substs: &'tcx Substs<'tcx>) @@ -2671,11 +2661,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { })) } + #[inline] pub fn mk_closure(self, closure_id: DefId, closure_substs: ClosureSubsts<'tcx>) -> Ty<'tcx> { self.mk_ty(Closure(closure_id, closure_substs)) } + #[inline] pub fn mk_generator(self, id: DefId, generator_substs: GeneratorSubsts<'tcx>, @@ -2684,32 +2676,39 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(Generator(id, generator_substs, movability)) } + #[inline] pub fn mk_generator_witness(self, types: ty::Binder<&'tcx List>>) -> Ty<'tcx> { self.mk_ty(GeneratorWitness(types)) } + #[inline] pub fn mk_var(self, v: TyVid) -> Ty<'tcx> { self.mk_infer(TyVar(v)) } + #[inline] pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { self.mk_infer(IntVar(v)) } + #[inline] pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> { self.mk_infer(FloatVar(v)) } + #[inline] pub fn mk_infer(self, it: InferTy) -> Ty<'tcx> { self.mk_ty(Infer(it)) } + #[inline] pub fn mk_ty_param(self, index: u32, name: InternedString) -> Ty<'tcx> { self.mk_ty(Param(ParamTy { idx: index, name: name })) } + #[inline] pub fn mk_self_type(self) -> Ty<'tcx> { self.mk_ty_param(0, keywords::SelfType.name().as_interned_str()) } @@ -2723,6 +2722,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + #[inline] pub fn mk_opaque(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { self.mk_ty(Opaque(def_id, substs)) } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 6f0e8d4f02680..20f64597b7876 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -374,6 +374,7 @@ pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> { + #[inline] pub fn new( tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, @@ -679,24 +680,31 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // vars. See comment on `shift_vars_through_binders` method in // `subst.rs` for more details. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +enum Direction { + In, + Out, +} + struct Shifter<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - current_index: ty::DebruijnIndex, amount: u32, + direction: Direction, } impl Shifter<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32) -> Self { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32, direction: Direction) -> Self { Shifter { tcx, current_index: ty::INNERMOST, amount, + direction, } } } -impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { +impl TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { @@ -712,7 +720,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { if self.amount == 0 || debruijn < self.current_index { r } else { - let shifted = ty::ReLateBound(debruijn.shifted_in(self.amount), br); + let debruijn = match self.direction { + Direction::In => debruijn.shifted_in(self.amount), + Direction::Out => { + assert!(debruijn.as_u32() >= self.amount); + debruijn.shifted_out(self.amount) + } + }; + let shifted = ty::ReLateBound(debruijn, br); self.tcx.mk_region(shifted) } } @@ -726,8 +741,15 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { if self.amount == 0 || debruijn < self.current_index { ty } else { + let debruijn = match self.direction { + Direction::In => debruijn.shifted_in(self.amount), + Direction::Out => { + assert!(debruijn.as_u32() >= self.amount); + debruijn.shifted_out(self.amount) + } + }; self.tcx.mk_ty( - ty::Bound(debruijn.shifted_in(self.amount), bound_ty) + ty::Bound(debruijn, bound_ty) ) } } @@ -760,7 +782,18 @@ pub fn shift_vars<'a, 'gcx, 'tcx, T>( debug!("shift_vars(value={:?}, amount={})", value, amount); - value.fold_with(&mut Shifter::new(tcx, amount)) + value.fold_with(&mut Shifter::new(tcx, amount, Direction::In)) +} + +pub fn shift_out_vars<'a, 'gcx, 'tcx, T>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + value: &T, + amount: u32 +) -> T where T: TypeFoldable<'tcx> { + debug!("shift_out_vars(value={:?}, amount={})", + value, amount); + + value.fold_with(&mut Shifter::new(tcx, amount, Direction::Out)) } /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b371f4532e5fa..4633ab1166347 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1275,6 +1275,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { self.skip_binder().projection_ty.item_def_id } + #[inline] pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'_, '_, '_>) -> PolyTraitRef<'tcx> { // Note: unlike with `TraitRef::to_poly_trait_ref()`, // `self.0.trait_ref` is permitted to have escaping regions. @@ -1633,6 +1634,7 @@ impl<'tcx> ParamEnv<'tcx> { /// there are no where clauses in scope. Hidden types (like `impl /// Trait`) are left hidden, so this is suitable for ordinary /// type-checking. + #[inline] pub fn empty() -> Self { Self::new(List::empty(), Reveal::UserFacing) } @@ -1644,11 +1646,13 @@ impl<'tcx> ParamEnv<'tcx> { /// /// N.B. If you want to have predicates in scope, use `ParamEnv::new`, /// or invoke `param_env.with_reveal_all()`. + #[inline] pub fn reveal_all() -> Self { Self::new(List::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. + #[inline] pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { @@ -2148,6 +2152,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + #[inline] pub fn variant_descr(&self) -> &'static str { match self.adt_kind() { AdtKind::Struct => "struct", diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 082c1bd5fea44..1b64a686794c0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -25,6 +25,7 @@ use std::rc::Rc; use std::iter; use rustc_target::spec::abi; use hir as ast; +use traits; pub type RelateResult<'tcx, T> = Result>; @@ -371,6 +372,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, bug!("var types encountered in super_relate_tys") } + (ty::Bound(..), _) | (_, ty::Bound(..)) => { + bug!("bound types encountered in super_relate_tys") + } + (&ty::Error, _) | (_, &ty::Error) => { Ok(tcx.types.err) @@ -394,6 +399,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(a) } + (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => { + Ok(a) + } + (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def => { @@ -556,8 +565,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_fn_ptr(fty)) } - (&ty::Projection(ref a_data), &ty::Projection(ref b_data)) => - { + (ty::UnnormalizedProjection(a_data), ty::UnnormalizedProjection(b_data)) => { + let projection_ty = relation.relate(a_data, b_data)?; + Ok(tcx.mk_ty(ty::UnnormalizedProjection(projection_ty))) + } + + // these two are already handled downstream in case of lazy normalization + (ty::Projection(a_data), ty::Projection(b_data)) => { let projection_ty = relation.relate(a_data, b_data)?; Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs)) } @@ -710,6 +724,283 @@ impl<'tcx> Relate<'tcx> for Kind<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &ty::TraitPredicate<'tcx>, + b: &ty::TraitPredicate<'tcx> + ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + Ok(ty::TraitPredicate { + trait_ref: relation.relate(&a.trait_ref, &b.trait_ref)?, + }) + } +} + +impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &ty::ProjectionPredicate<'tcx>, + b: &ty::ProjectionPredicate<'tcx>, + ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + Ok(ty::ProjectionPredicate { + projection_ty: relation.relate(&a.projection_ty, &b.projection_ty)?, + ty: relation.relate(&a.ty, &b.ty)?, + }) + } +} + +impl<'tcx> Relate<'tcx> for traits::WhereClause<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::WhereClause<'tcx>, + b: &traits::WhereClause<'tcx> + ) -> RelateResult<'tcx, traits::WhereClause<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + use traits::WhereClause::*; + match (a, b) { + (Implemented(a_pred), Implemented(b_pred)) => { + Ok(Implemented(relation.relate(a_pred, b_pred)?)) + } + + (ProjectionEq(a_pred), ProjectionEq(b_pred)) => { + Ok(ProjectionEq(relation.relate(a_pred, b_pred)?)) + } + + (RegionOutlives(a_pred), RegionOutlives(b_pred)) => { + Ok(RegionOutlives(ty::OutlivesPredicate( + relation.relate(&a_pred.0, &b_pred.0)?, + relation.relate(&a_pred.1, &b_pred.1)?, + ))) + } + + (TypeOutlives(a_pred), TypeOutlives(b_pred)) => { + Ok(TypeOutlives(ty::OutlivesPredicate( + relation.relate(&a_pred.0, &b_pred.0)?, + relation.relate(&a_pred.1, &b_pred.1)?, + ))) + } + + _ => Err(TypeError::Mismatch), + } + } +} + +impl<'tcx> Relate<'tcx> for traits::WellFormed<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::WellFormed<'tcx>, + b: &traits::WellFormed<'tcx> + ) -> RelateResult<'tcx, traits::WellFormed<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + use traits::WellFormed::*; + match (a, b) { + (Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)), + (Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)), + _ => Err(TypeError::Mismatch), + } + } +} + +impl<'tcx> Relate<'tcx> for traits::FromEnv<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::FromEnv<'tcx>, + b: &traits::FromEnv<'tcx> + ) -> RelateResult<'tcx, traits::FromEnv<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + use traits::FromEnv::*; + match (a, b) { + (Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)), + (Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)), + _ => Err(TypeError::Mismatch), + } + } +} + +impl<'tcx> Relate<'tcx> for traits::DomainGoal<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::DomainGoal<'tcx>, + b: &traits::DomainGoal<'tcx> + ) -> RelateResult<'tcx, traits::DomainGoal<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + use traits::DomainGoal::*; + match (a, b) { + (Holds(a_wc), Holds(b_wc)) => Ok(Holds(relation.relate(a_wc, b_wc)?)), + (WellFormed(a_wf), WellFormed(b_wf)) => Ok(WellFormed(relation.relate(a_wf, b_wf)?)), + (FromEnv(a_fe), FromEnv(b_fe)) => Ok(FromEnv(relation.relate(a_fe, b_fe)?)), + + (Normalize(a_pred), Normalize(b_pred)) => { + Ok(Normalize(relation.relate(a_pred, b_pred)?)) + } + + _ => Err(TypeError::Mismatch), + } + } +} + +impl<'tcx> Relate<'tcx> for traits::Goal<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::Goal<'tcx>, + b: &traits::Goal<'tcx> + ) -> RelateResult<'tcx, traits::Goal<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + use traits::GoalKind::*; + match (a, b) { + (Implies(a_clauses, a_goal), Implies(b_clauses, b_goal)) => { + let clauses = relation.relate(a_clauses, b_clauses)?; + let goal = relation.relate(a_goal, b_goal)?; + Ok(relation.tcx().mk_goal(Implies(clauses, goal))) + } + + (And(a_left, a_right), And(b_left, b_right)) => { + let left = relation.relate(a_left, b_left)?; + let right = relation.relate(a_right, b_right)?; + Ok(relation.tcx().mk_goal(And(left, right))) + } + + (Not(a_goal), Not(b_goal)) => { + let goal = relation.relate(a_goal, b_goal)?; + Ok(relation.tcx().mk_goal(Not(goal))) + } + + (DomainGoal(a_goal), DomainGoal(b_goal)) => { + let goal = relation.relate(a_goal, b_goal)?; + Ok(relation.tcx().mk_goal(DomainGoal(goal))) + } + + (Quantified(a_qkind, a_goal), Quantified(b_qkind, b_goal)) + if a_qkind == b_qkind => + { + let goal = relation.relate(a_goal, b_goal)?; + Ok(relation.tcx().mk_goal(Quantified(*a_qkind, goal))) + } + + (CannotProve, CannotProve) => Ok(*a), + + _ => Err(TypeError::Mismatch), + } + } +} + +impl<'tcx> Relate<'tcx> for traits::Goals<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::Goals<'tcx>, + b: &traits::Goals<'tcx> + ) -> RelateResult<'tcx, traits::Goals<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + if a.len() != b.len() { + return Err(TypeError::Mismatch); + } + + let tcx = relation.tcx(); + let goals = a.iter().zip(b.iter()).map(|(a, b)| relation.relate(a, b)); + Ok(tcx.mk_goals(goals)?) + } +} + +impl<'tcx> Relate<'tcx> for traits::Clause<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::Clause<'tcx>, + b: &traits::Clause<'tcx> + ) -> RelateResult<'tcx, traits::Clause<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + use traits::Clause::*; + match (a, b) { + (Implies(a_clause), Implies(b_clause)) => { + let clause = relation.relate(a_clause, b_clause)?; + Ok(Implies(clause)) + } + + (ForAll(a_clause), ForAll(b_clause)) => { + let clause = relation.relate(a_clause, b_clause)?; + Ok(ForAll(clause)) + } + + _ => Err(TypeError::Mismatch), + } + } +} + +impl<'tcx> Relate<'tcx> for traits::Clauses<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::Clauses<'tcx>, + b: &traits::Clauses<'tcx> + ) -> RelateResult<'tcx, traits::Clauses<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + if a.len() != b.len() { + return Err(TypeError::Mismatch); + } + + let tcx = relation.tcx(); + let clauses = a.iter().zip(b.iter()).map(|(a, b)| relation.relate(a, b)); + Ok(tcx.mk_clauses(clauses)?) + } +} + +impl<'tcx> Relate<'tcx> for traits::ProgramClause<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::ProgramClause<'tcx>, + b: &traits::ProgramClause<'tcx> + ) -> RelateResult<'tcx, traits::ProgramClause<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + Ok(traits::ProgramClause { + goal: relation.relate(&a.goal, &b.goal)?, + hypotheses: relation.relate(&a.hypotheses, &b.hypotheses)?, + category: traits::ProgramClauseCategory::Other, + }) + } +} + +impl<'tcx> Relate<'tcx> for traits::Environment<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::Environment<'tcx>, + b: &traits::Environment<'tcx> + ) -> RelateResult<'tcx, traits::Environment<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + Ok(traits::Environment { + clauses: relation.relate(&a.clauses, &b.clauses)?, + }) + } +} + +impl<'tcx, G> Relate<'tcx> for traits::InEnvironment<'tcx, G> + where G: Relate<'tcx> +{ + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &traits::InEnvironment<'tcx, G>, + b: &traits::InEnvironment<'tcx, G> + ) -> RelateResult<'tcx, traits::InEnvironment<'tcx, G>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a + { + Ok(traits::InEnvironment { + environment: relation.relate(&a.environment, &b.environment)?, + goal: relation.relate(&a.goal, &b.goal)?, + }) + } +} + /////////////////////////////////////////////////////////////////////////// // Error handling diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a18e3a275467d..1416cb17feaed 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -667,6 +667,7 @@ impl<'tcx> TraitRef<'tcx> { } } + #[inline] pub fn self_ty(&self) -> Ty<'tcx> { self.substs.type_at(0) } @@ -978,15 +979,18 @@ impl<'tcx> FnSig<'tcx> { pub type PolyFnSig<'tcx> = Binder>; impl<'tcx> PolyFnSig<'tcx> { + #[inline] pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> { self.map_bound_ref(|fn_sig| fn_sig.inputs()) } + #[inline] pub fn input(&self, index: usize) -> ty::Binder> { self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) } pub fn inputs_and_output(&self) -> ty::Binder<&'tcx List>> { self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output) } + #[inline] pub fn output(&self) -> ty::Binder> { self.map_bound_ref(|fn_sig| fn_sig.output()) } @@ -1548,6 +1552,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_ty_var(&self) -> bool { match self.sty { Infer(TyVar(_)) => true, @@ -1732,6 +1737,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_integral(&self) -> bool { match self.sty { Infer(IntVar(_)) | Int(_) | Uint(_) => true, @@ -1762,6 +1768,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_fp(&self) -> bool { match self.sty { Infer(FloatVar(_)) | Float(_) => true, @@ -1845,6 +1852,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { match self.sty { Adt(adt, _) => Some(adt), diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 7945d381760a1..4eb920324bd00 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -23,7 +23,7 @@ use llvm_util; use ModuleLlvm; use rustc_codegen_ssa::{ModuleCodegen, CompiledModule}; use rustc::util::common::time_ext; -use rustc_fs_util::{path2cstr, link_or_copy}; +use rustc_fs_util::{path_to_c_string, link_or_copy}; use rustc_data_structures::small_c_str::SmallCStr; use errors::{self, Handler, FatalError}; use type_::Type; @@ -80,7 +80,7 @@ pub fn write_output_file( output: &Path, file_type: llvm::FileType) -> Result<(), FatalError> { unsafe { - let output_c = path2cstr(output); + let output_c = path_to_c_string(output); let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type); if result.into_result().is_err() { let msg = format!("could not write output to {}", output.display()); @@ -211,7 +211,7 @@ pub(crate) fn save_temp_bitcode( let ext = format!("{}.bc", name); let cgu = Some(&module.name[..]); let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); - let cstr = path2cstr(&path); + let cstr = path_to_c_string(&path); let llmod = module.module_llvm.llmod(); llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); } @@ -324,7 +324,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, if config.emit_no_opt_bc { let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); - let out = path2cstr(&out); + let out = path_to_c_string(&out); llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } @@ -530,7 +530,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, || -> Result<(), FatalError> { if config.emit_ir { let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); - let out = path2cstr(&out); + let out = path_to_c_string(&out); extern "C" fn demangle_callback(input_ptr: *const c_char, input_len: size_t, diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 81f2769800d2f..47e92fbe87d31 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -39,7 +39,7 @@ use rustc::ty::layout::{self, Align, HasDataLayout, Integer, IntegerExt, LayoutO PrimitiveExt, Size, TyLayout}; use rustc::session::config; use rustc::util::nodemap::FxHashMap; -use rustc_fs_util::path2cstr; +use rustc_fs_util::path_to_c_string; use rustc_data_structures::small_c_str::SmallCStr; use libc::{c_uint, c_longlong}; @@ -892,7 +892,7 @@ pub fn compile_unit_metadata(tcx: TyCtxt, }; fn path_to_mdstring(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value { - let path_str = path2cstr(path); + let path_str = path_to_c_string(path); unsafe { llvm::LLVMMDStringInContext(llcx, path_str.as_ptr(), diff --git a/src/librustc_codegen_llvm/llvm/archive_ro.rs b/src/librustc_codegen_llvm/llvm/archive_ro.rs index 2a77f256e3a0c..d5c73fecf814a 100644 --- a/src/librustc_codegen_llvm/llvm/archive_ro.rs +++ b/src/librustc_codegen_llvm/llvm/archive_ro.rs @@ -10,10 +10,10 @@ //! A wrapper around LLVM's archive (.a) code -use std::ffi::CString; use std::path::Path; use std::slice; use std::str; +use rustc_fs_util::path_to_c_string; pub struct ArchiveRO { pub raw: &'static mut super::Archive, @@ -38,24 +38,12 @@ impl ArchiveRO { /// raised. pub fn open(dst: &Path) -> Result { return unsafe { - let s = path2cstr(dst); + let s = path_to_c_string(dst); let ar = super::LLVMRustOpenArchive(s.as_ptr()).ok_or_else(|| { super::last_error().unwrap_or_else(|| "failed to open archive".to_owned()) })?; Ok(ArchiveRO { raw: ar }) }; - - #[cfg(unix)] - fn path2cstr(p: &Path) -> CString { - use std::os::unix::prelude::*; - use std::ffi::OsStr; - let p: &OsStr = p.as_ref(); - CString::new(p.as_bytes()).unwrap() - } - #[cfg(windows)] - fn path2cstr(p: &Path) -> CString { - CString::new(p.to_str().unwrap()).unwrap() - } } pub fn iter(&self) -> Iter { diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index 7752465d885bb..5605f64c2e72c 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -18,7 +18,7 @@ use rustc_data_structures::owning_ref::OwningRef; use std::path::Path; use std::ptr; use std::slice; -use rustc_fs_util::path2cstr; +use rustc_fs_util::path_to_c_string; pub use rustc_data_structures::sync::MetadataRef; @@ -57,7 +57,7 @@ impl MetadataLoader for LlvmMetadataLoader { filename: &Path) -> Result { unsafe { - let buf = path2cstr(filename); + let buf = path_to_c_string(filename); let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()) .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?; let of = ObjectFile::new(mb) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index b0575b841d5d5..24a70dc797771 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -161,7 +161,11 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { LinkerFlavor::Lld(_) => "lld", }), flavor)), (Some(linker), None) => { - let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| { + let stem = if linker.extension().and_then(|ext| ext.to_str()) == Some("exe") { + linker.file_stem().and_then(|stem| stem.to_str()) + } else { + linker.to_str() + }.unwrap_or_else(|| { sess.fatal("couldn't extract file stem from specified linker"); }).to_owned(); diff --git a/src/librustc_data_structures/interner.rs b/src/librustc_data_structures/interner.rs new file mode 100644 index 0000000000000..29e5aefee7f0b --- /dev/null +++ b/src/librustc_data_structures/interner.rs @@ -0,0 +1,68 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::hash::Hash; +use std::hash::BuildHasher; +use std::hash::Hasher; +use std::collections::HashMap; +use std::collections::hash_map::RawEntryMut; +use std::borrow::Borrow; + +pub trait HashInterner { + fn intern_ref K>(&mut self, value: &Q, make: F) -> K + where K: Borrow, + Q: Hash + Eq; + + fn intern K>(&mut self, value: Q, make: F) -> K + where K: Borrow, + Q: Hash + Eq; +} + +impl HashInterner for HashMap { + #[inline] + fn intern_ref K>(&mut self, value: &Q, make: F) -> K + where K: Borrow, + Q: Hash + Eq + { + let mut hasher = self.hasher().build_hasher(); + value.hash(&mut hasher); + let hash = hasher.finish(); + let entry = self.raw_entry_mut().from_key_hashed_nocheck(hash, value); + + match entry { + RawEntryMut::Occupied(e) => *e.key(), + RawEntryMut::Vacant(e) => { + let v = make(); + e.insert_hashed_nocheck(hash, v, ()); + v + } + } + } + + #[inline] + fn intern K>(&mut self, value: Q, make: F) -> K + where K: Borrow, + Q: Hash + Eq + { + let mut hasher = self.hasher().build_hasher(); + value.hash(&mut hasher); + let hash = hasher.finish(); + let entry = self.raw_entry_mut().from_key_hashed_nocheck(hash, &value); + + match entry { + RawEntryMut::Occupied(e) => *e.key(), + RawEntryMut::Vacant(e) => { + let v = make(value); + e.insert_hashed_nocheck(hash, v, ()); + v + } + } + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 135abebdacb7a..96cb235a93362 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -29,6 +29,7 @@ #![feature(nll)] #![feature(allow_internal_unstable)] #![feature(vec_resize_with)] +#![feature(hash_raw_entry)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] @@ -66,6 +67,7 @@ pub mod flock; pub mod fx; pub mod graph; pub mod indexed_vec; +pub mod interner; pub mod obligation_forest; pub mod owning_ref; pub mod ptr_key; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index c7ba31e339570..fb8093d1d77a7 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -530,7 +530,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { s.s.space()?; s.s.word("as")?; s.s.space()?; - s.s.word(&self.tables.get().expr_ty(expr).to_string())?; + s.s.word(self.tables.get().expr_ty(expr).to_string())?; s.pclose() } _ => Ok(()), diff --git a/src/librustc_fs_util/lib.rs b/src/librustc_fs_util/lib.rs index ffe420b109d3e..1b0ff4f861c7b 100644 --- a/src/librustc_fs_util/lib.rs +++ b/src/librustc_fs_util/lib.rs @@ -116,13 +116,13 @@ pub fn rename_or_copy_remove, Q: AsRef>(p: P, } #[cfg(unix)] -pub fn path2cstr(p: &Path) -> CString { - use std::os::unix::prelude::*; +pub fn path_to_c_string(p: &Path) -> CString { + use std::os::unix::ffi::OsStrExt; use std::ffi::OsStr; let p: &OsStr = p.as_ref(); CString::new(p.as_bytes()).unwrap() } #[cfg(windows)] -pub fn path2cstr(p: &Path) -> CString { +pub fn path_to_c_string(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index cf4f913080783..225e2841fb0ac 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -10,10 +10,11 @@ use borrow_check::nll::constraints::OutlivesConstraint; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; -use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; +use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate, NormalizationStrategy}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::ConstraintCategory; use rustc::traits::query::Fallible; +use rustc::traits::DomainGoal; use rustc::ty::relate::TypeRelation; use rustc::ty::{self, Ty}; @@ -38,7 +39,7 @@ pub(super) fn relate_types<'tcx>( TypeRelating::new( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - v, + v ).relate(&a, &b)?; Ok(()) } @@ -115,4 +116,16 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { }); } } + + fn push_domain_goal(&mut self, _: DomainGoal<'tcx>) { + bug!("should never be invoked with eager normalization") + } + + fn normalization() -> NormalizationStrategy { + NormalizationStrategy::Eager + } + + fn forbid_inference_vars() -> bool { + true + } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 6dba020120f84..3a6ee6da42215 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -985,7 +985,7 @@ fn collect_and_partition_mono_items<'a, 'tcx>( output.push_str(" @@"); let mut empty = Vec::new(); let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); + cgus.as_mut_slice().sort_by_cached_key(|&(ref name, _)| name.clone()); cgus.dedup(); for &(ref cgu_name, (linkage, _)) in cgus.iter() { output.push_str(" "); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 09fe7b14c7973..bcee6d75b5a4a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -895,145 +895,160 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { let mut is_shuffle = false; let mut is_const_fn = false; let mut is_promotable_const_fn = false; - if let ty::FnDef(def_id, _) = fn_ty.sty { - callee_def_id = Some(def_id); - match self.tcx.fn_sig(def_id).abi() { - Abi::RustIntrinsic | - Abi::PlatformIntrinsic => { - assert!(!self.tcx.is_const_fn(def_id)); - match &self.tcx.item_name(def_id).as_str()[..] { - | "size_of" - | "min_align_of" - | "needs_drop" - | "type_id" - | "bswap" - | "bitreverse" - | "ctpop" - | "cttz" - | "cttz_nonzero" - | "ctlz" - | "ctlz_nonzero" - | "overflowing_add" - | "overflowing_sub" - | "overflowing_mul" - | "unchecked_shl" - | "unchecked_shr" - | "rotate_left" - | "rotate_right" - | "add_with_overflow" - | "sub_with_overflow" - | "mul_with_overflow" - // no need to check feature gates, intrinsics are only callable from the - // libstd or with forever unstable feature gates - => is_const_fn = true, - // special intrinsic that can be called diretly without an intrinsic - // feature gate needs a language feature gate - "transmute" => { - // never promote transmute calls - if self.mode != Mode::Fn { - is_const_fn = true; - // const eval transmute calls only with the feature gate - if !self.tcx.features().const_transmute { - emit_feature_err( - &self.tcx.sess.parse_sess, "const_transmute", - self.span, GateIssue::Language, - &format!("The use of std::mem::transmute() \ - is gated in {}s", self.mode)); + match fn_ty.sty { + ty::FnDef(def_id, _) => { + callee_def_id = Some(def_id); + match self.tcx.fn_sig(def_id).abi() { + Abi::RustIntrinsic | + Abi::PlatformIntrinsic => { + assert!(!self.tcx.is_const_fn(def_id)); + match &self.tcx.item_name(def_id).as_str()[..] { + | "size_of" + | "min_align_of" + | "needs_drop" + | "type_id" + | "bswap" + | "bitreverse" + | "ctpop" + | "cttz" + | "cttz_nonzero" + | "ctlz" + | "ctlz_nonzero" + | "overflowing_add" + | "overflowing_sub" + | "overflowing_mul" + | "unchecked_shl" + | "unchecked_shr" + | "rotate_left" + | "rotate_right" + | "add_with_overflow" + | "sub_with_overflow" + | "mul_with_overflow" + // no need to check feature gates, intrinsics are only callable + // from the libstd or with forever unstable feature gates + => is_const_fn = true, + // special intrinsic that can be called diretly without an intrinsic + // feature gate needs a language feature gate + "transmute" => { + // never promote transmute calls + if self.mode != Mode::Fn { + is_const_fn = true; + // const eval transmute calls only with the feature gate + if !self.tcx.features().const_transmute { + emit_feature_err( + &self.tcx.sess.parse_sess, "const_transmute", + self.span, GateIssue::Language, + &format!("The use of std::mem::transmute() \ + is gated in {}s", self.mode)); + } } } - } - name if name.starts_with("simd_shuffle") => { - is_shuffle = true; - } + name if name.starts_with("simd_shuffle") => { + is_shuffle = true; + } - _ => {} - } - } - _ => { - // in normal functions we only care about promotion - if self.mode == Mode::Fn { - // never promote const fn calls of - // functions without #[rustc_promotable] - if self.tcx.is_promotable_const_fn(def_id) { - is_const_fn = true; - is_promotable_const_fn = true; - } else if self.tcx.is_const_fn(def_id) { - is_const_fn = true; + _ => {} } - } else { - // stable const fn or unstable const fns with their feature gate - // active - if self.tcx.is_const_fn(def_id) { - is_const_fn = true; - } else if self.is_const_panic_fn(def_id) { - // check the const_panic feature gate - // FIXME: cannot allow this inside `allow_internal_unstable` because - // that would make `panic!` insta stable in constants, since the - // macro is marked with the attr - if self.tcx.features().const_panic { + } + _ => { + // in normal functions we only care about promotion + if self.mode == Mode::Fn { + // never promote const fn calls of + // functions without #[rustc_promotable] + if self.tcx.is_promotable_const_fn(def_id) { is_const_fn = true; - } else { - // don't allow panics in constants without the feature gate - emit_feature_err( - &self.tcx.sess.parse_sess, - "const_panic", - self.span, - GateIssue::Language, - &format!("panicking in {}s is unstable", self.mode), - ); - } - } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) { - // check `#[unstable]` const fns or `#[rustc_const_unstable]` - // functions without the feature gate active in this crate to report - // a better error message than the one below - if self.span.allows_unstable() { - // `allow_internal_unstable` can make such calls stable + is_promotable_const_fn = true; + } else if self.tcx.is_const_fn(def_id) { is_const_fn = true; - } else { - let mut err = self.tcx.sess.struct_span_err(self.span, - &format!("`{}` is not yet stable as a const fn", - self.tcx.item_path_str(def_id))); - help!(&mut err, - "in Nightly builds, add `#![feature({})]` \ - to the crate attributes to enable", - feature); - err.emit(); } } else { - // FIXME(#24111) Remove this check when const fn stabilizes - let (msg, note) = if let UnstableFeatures::Disallow = - self.tcx.sess.opts.unstable_features { - (format!("calls in {}s are limited to \ - tuple structs and tuple variants", - self.mode), - Some("a limited form of compile-time function \ - evaluation is available on a nightly \ - compiler via `const fn`")) + // stable const fn or unstable const fns with their feature gate + // active + if self.tcx.is_const_fn(def_id) { + is_const_fn = true; + } else if self.is_const_panic_fn(def_id) { + // check the const_panic feature gate + // FIXME: cannot allow this inside `allow_internal_unstable` + // because that would make `panic!` insta stable in constants, + // since the macro is marked with the attr + if self.tcx.features().const_panic { + is_const_fn = true; + } else { + // don't allow panics in constants without the feature gate + emit_feature_err( + &self.tcx.sess.parse_sess, + "const_panic", + self.span, + GateIssue::Language, + &format!("panicking in {}s is unstable", self.mode), + ); + } + } else if let Some(feat) = self.tcx.is_unstable_const_fn(def_id) { + // check `#[unstable]` const fns or `#[rustc_const_unstable]` + // functions without the feature gate active in this crate to + // report a better error message than the one below + if self.span.allows_unstable() { + // `allow_internal_unstable` can make such calls stable + is_const_fn = true; + } else { + let mut err = self.tcx.sess.struct_span_err(self.span, + &format!("`{}` is not yet stable as a const fn", + self.tcx.item_path_str(def_id))); + help!(&mut err, + "in Nightly builds, add `#![feature({})]` \ + to the crate attributes to enable", + feat); + err.emit(); + } } else { - (format!("calls in {}s are limited \ - to constant functions, \ - tuple structs and tuple variants", - self.mode), - None) - }; - let mut err = struct_span_err!( - self.tcx.sess, - self.span, - E0015, - "{}", - msg, - ); - if let Some(note) = note { - err.span_note(self.span, note); + // FIXME(#24111) Remove this check when const fn stabilizes + let (msg, note) = if let UnstableFeatures::Disallow = + self.tcx.sess.opts.unstable_features { + (format!("calls in {}s are limited to \ + tuple structs and tuple variants", + self.mode), + Some("a limited form of compile-time function \ + evaluation is available on a nightly \ + compiler via `const fn`")) + } else { + (format!("calls in {}s are limited \ + to constant functions, \ + tuple structs and tuple variants", + self.mode), + None) + }; + let mut err = struct_span_err!( + self.tcx.sess, + self.span, + E0015, + "{}", + msg, + ); + if let Some(note) = note { + err.span_note(self.span, note); + } + err.emit(); } - err.emit(); } } } + }, + ty::FnPtr(_) => { + if self.mode != Mode::Fn { + let mut err = self.tcx.sess.struct_span_err( + self.span, + &format!("function pointers are not allowed in const fn")); + err.emit(); + } + }, + _ => { + self.not_const(); + return } } + let constant_arguments = callee_def_id.and_then(|id| { args_required_const(self.tcx, id) }); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index fbd6f6edd31c5..6d9abbf5af2ac 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -969,7 +969,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { Some(poly_projection_predicate.skip_binder() .projection_ty.trait_ref(self.tcx)) } - ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => None, _ => bug!("unexpected predicate: {:?}", predicate), }; if let Some(trait_ref) = trait_ref { diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index 25a6af284b572..58a8d2abd9962 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -9,13 +9,25 @@ // except according to those terms. mod program_clauses; - -use chalk_engine::fallible::Fallible as ChalkEngineFallible; -use chalk_engine::{context, hh::HhGoal, DelayedLiteral, Literal, ExClause}; +mod resolvent_ops; +mod unify; + +use chalk_engine::fallible::{Fallible, NoSolution}; +use chalk_engine::{ + context, + hh::HhGoal, + DelayedLiteral, + Literal, + ExClause +}; +use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; use rustc::infer::canonical::{ - Canonical, CanonicalVarValues, OriginalQueryValues, QueryRegionConstraint, QueryResponse, + Canonical, + CanonicalVarValues, + OriginalQueryValues, + QueryResponse, + Certainty, }; -use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc::traits::{ DomainGoal, ExClauseFold, @@ -27,14 +39,15 @@ use rustc::traits::{ Environment, InEnvironment, }; +use rustc::ty::{self, TyCtxt}; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::subst::{Kind, UnpackedKind}; -use rustc::ty::{self, TyCtxt}; +use syntax_pos::DUMMY_SP; use std::fmt::{self, Debug}; use std::marker::PhantomData; -use syntax_pos::DUMMY_SP; +use self::unify::*; #[derive(Copy, Clone, Debug)] crate struct ChalkArenas<'gcx> { @@ -55,10 +68,12 @@ crate struct ChalkInferenceContext<'cx, 'gcx: 'tcx, 'tcx: 'cx> { #[derive(Copy, Clone, Debug)] crate struct UniverseMap; +crate type RegionConstraint<'tcx> = ty::OutlivesPredicate, ty::Region<'tcx>>; + #[derive(Clone, Debug, PartialEq, Eq, Hash)] crate struct ConstrainedSubst<'tcx> { subst: CanonicalVarValues<'tcx>, - constraints: Vec>, + constraints: Vec>, } BraceStructTypeFoldableImpl! { @@ -86,7 +101,7 @@ impl context::Context for ChalkArenas<'tcx> { type GoalInEnvironment = InEnvironment<'tcx, Goal<'tcx>>; - type RegionConstraint = QueryRegionConstraint<'tcx>; + type RegionConstraint = RegionConstraint<'tcx>; type Substitution = CanonicalVarValues<'tcx>; @@ -104,7 +119,7 @@ impl context::Context for ChalkArenas<'tcx> { type ProgramClauses = Vec>; - type UnificationResult = InferOk<'tcx, ()>; + type UnificationResult = UnificationResult<'tcx>; fn goal_in_environment( env: &Environment<'tcx>, @@ -118,9 +133,34 @@ impl context::AggregateOps> for ChalkContext<'cx, 'gcx> { fn make_solution( &self, _root_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - _simplified_answers: impl context::AnswerStream>, + mut simplified_answers: impl context::AnswerStream>, ) -> Option>> { - unimplemented!() + use chalk_engine::SimplifiedAnswer; + + if simplified_answers.peek_answer().is_none() { + return None; + } + + let SimplifiedAnswer { subst, ambiguous } = simplified_answers + .next_answer() + .unwrap(); + + let ambiguous = simplified_answers.peek_answer().is_some() || ambiguous; + + Some(subst.unchecked_map(|subst| { + QueryResponse { + var_values: subst.subst, + region_constraints: subst.constraints + .into_iter() + .map(|c| ty::Binder::bind(c)) + .collect(), + certainty: match ambiguous { + true => Certainty::Ambiguous, + false => Certainty::Proven, + }, + value: (), + } + })) } } @@ -197,7 +237,7 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { fn is_trivial_substitution( u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, + canonical_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, ) -> bool { let subst = &canonical_subst.value.subst; assert_eq!(u_canon.variables.len(), subst.var_values.len()); @@ -282,30 +322,6 @@ impl context::InferenceTable, ChalkArenas<'tcx>> } } -impl context::ResolventOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'gcx, 'tcx> -{ - fn resolvent_clause( - &mut self, - _environment: &Environment<'tcx>, - _goal: &DomainGoal<'tcx>, - _subst: &CanonicalVarValues<'tcx>, - _clause: &Clause<'tcx>, - ) -> chalk_engine::fallible::Fallible>> { - panic!() - } - - fn apply_answer_subst( - &mut self, - _ex_clause: ChalkExClause<'tcx>, - _selected_goal: &InEnvironment<'tcx, Goal<'tcx>>, - _answer_table_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - _canonical_answer_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, - ) -> chalk_engine::fallible::Fallible> { - panic!() - } -} - impl context::TruncateOps, ChalkArenas<'tcx>> for ChalkInferenceContext<'cx, 'gcx, 'tcx> { @@ -376,7 +392,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn canonicalize_constrained_subst( &mut self, subst: CanonicalVarValues<'tcx>, - constraints: Vec>, + constraints: Vec>, ) -> Canonical<'gcx, ConstrainedSubst<'gcx>> { self.infcx.canonicalize_response(&ConstrainedSubst { subst, constraints }) } @@ -400,11 +416,13 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn unify_parameters( &mut self, - _environment: &Environment<'tcx>, - _a: &Kind<'tcx>, - _b: &Kind<'tcx>, - ) -> ChalkEngineFallible> { - panic!() + environment: &Environment<'tcx>, + a: &Kind<'tcx>, + b: &Kind<'tcx>, + ) -> Fallible> { + self.infcx.commit_if_ok(|_| { + unify(self.infcx, *environment, a, b).map_err(|_| NoSolution) + }) } fn sink_answer_subset( @@ -421,11 +439,22 @@ impl context::UnificationOps, ChalkArenas<'tcx>> panic!("lift") } - fn into_ex_clause(&mut self, _result: InferOk<'tcx, ()>, _ex_clause: &mut ChalkExClause<'tcx>) { - panic!("TBD") + fn into_ex_clause( + &mut self, + result: UnificationResult<'tcx>, + ex_clause: &mut ChalkExClause<'tcx> + ) { + into_ex_clause(result, ex_clause); } } +crate fn into_ex_clause(result: UnificationResult<'tcx>, ex_clause: &mut ChalkExClause<'tcx>) { + ex_clause.subgoals.extend( + result.goals.into_iter().map(Literal::Positive) + ); + ex_clause.constraints.extend(result.constraints); +} + type ChalkHhGoal<'tcx> = HhGoal>; type ChalkExClause<'tcx> = ExClause>; diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs new file mode 100644 index 0000000000000..df6458a766d4e --- /dev/null +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -0,0 +1,241 @@ +use chalk_engine::fallible::{Fallible, NoSolution}; +use chalk_engine::{ + context, + Literal, + ExClause +}; +use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc::traits::{ + DomainGoal, + Goal, + GoalKind, + Clause, + ProgramClause, + Environment, + InEnvironment, +}; +use rustc::ty::{self, Ty}; +use rustc::ty::subst::Kind; +use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use syntax_pos::DUMMY_SP; + +use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst}; +use super::unify::*; + +impl context::ResolventOps, ChalkArenas<'tcx>> + for ChalkInferenceContext<'cx, 'gcx, 'tcx> +{ + fn resolvent_clause( + &mut self, + environment: &Environment<'tcx>, + goal: &DomainGoal<'tcx>, + subst: &CanonicalVarValues<'tcx>, + clause: &Clause<'tcx>, + ) -> Fallible>> { + use chalk_engine::context::UnificationOps; + + self.infcx.probe(|_| { + let ProgramClause { + goal: consequence, + hypotheses, + .. + } = match clause { + Clause::Implies(program_clause) => *program_clause, + Clause::ForAll(program_clause) => self.infcx.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + program_clause + ).0, + }; + + let result = unify(self.infcx, *environment, goal, &consequence) + .map_err(|_| NoSolution)?; + + let mut ex_clause = ExClause { + subst: subst.clone(), + delayed_literals: vec![], + constraints: vec![], + subgoals: vec![], + }; + + self.into_ex_clause(result, &mut ex_clause); + + ex_clause.subgoals.extend( + hypotheses.iter().map(|g| match g { + GoalKind::Not(g) => Literal::Negative(environment.with(*g)), + g => Literal::Positive(environment.with(*g)), + }) + ); + + let canonical_ex_clause = self.canonicalize_ex_clause(&ex_clause); + Ok(canonical_ex_clause) + }) + } + + fn apply_answer_subst( + &mut self, + ex_clause: ChalkExClause<'tcx>, + selected_goal: &InEnvironment<'tcx, Goal<'tcx>>, + answer_table_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, + canonical_answer_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, + ) -> Fallible> { + let (answer_subst, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( + DUMMY_SP, + canonical_answer_subst + ); + + let mut substitutor = AnswerSubstitutor { + infcx: self.infcx, + environment: selected_goal.environment, + answer_subst: answer_subst.subst, + binder_index: ty::INNERMOST, + ex_clause, + }; + + substitutor.relate(&answer_table_goal.value, &selected_goal) + .map_err(|_| NoSolution)?; + + let mut ex_clause = substitutor.ex_clause; + ex_clause.constraints.extend(answer_subst.constraints); + Ok(ex_clause) + } +} + +struct AnswerSubstitutor<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + environment: Environment<'tcx>, + answer_subst: CanonicalVarValues<'tcx>, + binder_index: ty::DebruijnIndex, + ex_clause: ChalkExClause<'tcx>, +} + +impl AnswerSubstitutor<'cx, 'gcx, 'tcx> { + fn unify_free_answer_var( + &mut self, + answer_var: ty::BoundVar, + pending: Kind<'tcx> + ) -> RelateResult<'tcx, ()> { + let answer_param = &self.answer_subst.var_values[answer_var]; + let pending = &ty::fold::shift_out_vars( + self.infcx.tcx, + &pending, + self.binder_index.as_u32() + ); + + super::into_ex_clause( + unify(self.infcx, self.environment, answer_param, pending)?, + &mut self.ex_clause + ); + + Ok(()) + } +} + +impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { + fn tcx(&self) -> ty::TyCtxt<'cx, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn tag(&self) -> &'static str { + "chalk_context::answer_substitutor" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + a: &T, + b: &T, + ) -> RelateResult<'tcx, T> { + // We don't care about variance. + self.relate(a, b) + } + + fn binders>( + &mut self, + a: &ty::Binder, + b: &ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> { + self.binder_index.shift_in(1); + let result = self.relate(a.skip_binder(), b.skip_binder())?; + self.binder_index.shift_out(1); + Ok(ty::Binder::bind(result)) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + let b = self.infcx.shallow_resolve(b); + + if let &ty::Bound(debruijn, bound_ty) = &a.sty { + // Free bound var + if debruijn == self.binder_index { + self.unify_free_answer_var(bound_ty.var, b.into())?; + return Ok(b); + } + } + + match (&a.sty, &b.sty) { + (&ty::Bound(a_debruijn, a_bound), &ty::Bound(b_debruijn, b_bound)) => { + assert_eq!(a_debruijn, b_debruijn); + assert_eq!(a_bound.var, b_bound.var); + Ok(a) + } + + // Those should have been canonicalized away. + (ty::Placeholder(..), _) => { + bug!("unexpected placeholder ty in `AnswerSubstitutor`: {:?} ", a); + } + + // Everything else should just be a perfect match as well, + // and we forbid inference variables. + _ => match ty::relate::super_relate_tys(self, a, b) { + Ok(ty) => Ok(ty), + Err(err) => bug!("type mismatch in `AnswerSubstitutor`: {}", err), + } + } + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + let b = match b { + &ty::ReVar(vid) => self.infcx + .borrow_region_constraints() + .opportunistic_resolve_var(self.infcx.tcx, vid), + + other => other, + }; + + if let &ty::ReLateBound(debruijn, bound) = a { + // Free bound region + if debruijn == self.binder_index { + self.unify_free_answer_var(bound.assert_bound_var(), b.into())?; + return Ok(b); + } + } + + match (a, b) { + (&ty::ReLateBound(a_debruijn, a_bound), &ty::ReLateBound(b_debruijn, b_bound)) => { + assert_eq!(a_debruijn, b_debruijn); + assert_eq!(a_bound.assert_bound_var(), b_bound.assert_bound_var()); + } + + (ty::ReStatic, ty::ReStatic) | + (ty::ReErased, ty::ReErased) | + (ty::ReEmpty, ty::ReEmpty) => (), + + (&ty::ReFree(a_free), &ty::ReFree(b_free)) => { + assert_eq!(a_free, b_free); + } + + _ => bug!("unexpected regions in `AnswerSubstitutor`: {:?}, {:?}", a, b), + } + + Ok(a) + } +} diff --git a/src/librustc_traits/chalk_context/unify.rs b/src/librustc_traits/chalk_context/unify.rs new file mode 100644 index 0000000000000..3a9c3918d137e --- /dev/null +++ b/src/librustc_traits/chalk_context/unify.rs @@ -0,0 +1,98 @@ +use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate, NormalizationStrategy}; +use rustc::infer::{InferCtxt, RegionVariableOrigin}; +use rustc::traits::{DomainGoal, Goal, Environment, InEnvironment}; +use rustc::ty::relate::{Relate, TypeRelation, RelateResult}; +use rustc::ty; +use syntax_pos::DUMMY_SP; + +crate struct UnificationResult<'tcx> { + crate goals: Vec>>, + crate constraints: Vec>, +} + +crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>( + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + environment: Environment<'tcx>, + a: &T, + b: &T +) -> RelateResult<'tcx, UnificationResult<'tcx>> { + let mut delegate = ChalkTypeRelatingDelegate::new( + infcx, + environment + ); + + TypeRelating::new( + infcx, + &mut delegate, + ty::Variance::Invariant + ).relate(a, b)?; + + Ok(UnificationResult { + goals: delegate.goals, + constraints: delegate.constraints, + }) +} + +struct ChalkTypeRelatingDelegate<'me, 'gcx: 'tcx, 'tcx: 'me> { + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + environment: Environment<'tcx>, + goals: Vec>>, + constraints: Vec>, +} + +impl ChalkTypeRelatingDelegate<'me, 'gcx, 'tcx> { + fn new( + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + environment: Environment<'tcx>, + ) -> Self { + Self { + infcx, + environment, + goals: Vec::new(), + constraints: Vec::new(), + } + } +} + +impl TypeRelatingDelegate<'tcx> for &mut ChalkTypeRelatingDelegate<'_, '_, 'tcx> { + fn create_next_universe(&mut self) -> ty::UniverseIndex { + self.infcx.create_next_universe() + } + + fn next_existential_region_var(&mut self) -> ty::Region<'tcx> { + self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) + } + + fn next_placeholder_region( + &mut self, + placeholder: ty::PlaceholderRegion + ) -> ty::Region<'tcx> { + self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder)) + } + + fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + self.infcx.next_region_var_in_universe( + RegionVariableOrigin::MiscVariable(DUMMY_SP), + universe + ) + } + + fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + self.constraints.push(ty::OutlivesPredicate(sup.into(), sub)); + } + + fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) { + let goal = self.environment.with( + self.infcx.tcx.mk_goal(domain_goal.into_goal()) + ); + self.goals.push(goal); + } + + fn normalization() -> NormalizationStrategy { + NormalizationStrategy::Lazy + } + + fn forbid_inference_vars() -> bool { + false + } +} diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 22a96d4e908ca..103331894ff1e 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -185,7 +185,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { Some(orig_name) => format!("use {} as {};", orig_name, item.name), None => format!("use {};", item.name), }; - let replacement = visibility_qualified(&item.vis, &base_replacement); + let replacement = visibility_qualified(&item.vis, base_replacement); tcx.struct_span_lint_node(lint, id, extern_crate.span, msg) .span_suggestion_short_with_applicability( extern_crate.span, diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 3e028d755c6d4..cbd642dd6ad91 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -86,7 +86,7 @@ impl Encodable for VecDeque { impl Decodable for VecDeque { fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { - let mut deque: VecDeque = VecDeque::new(); + let mut deque: VecDeque = VecDeque::with_capacity(len); for i in 0..len { deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?); } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 2b1d515c83b75..c1446218367e4 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -47,6 +47,9 @@ backtrace = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] +# Make panics and failed asserts immediately abort without formatting any message +panic_immediate_abort = ["core/panic_immediate_abort"] + # An off-by-default feature which enables a linux-syscall-like ABI for libstd to # interoperate with the host environment. Currently not well documented and # requires rebuilding the standard library to use it. diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 7c717d832fa54..349aa029ba8cb 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -849,6 +849,7 @@ impl HashMap /// let mut map: HashMap<&str, i32> = HashMap::new(); /// map.reserve(10); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { match self.reserve_internal(additional, Infallible) { @@ -880,6 +881,7 @@ impl HashMap self.reserve_internal(additional, Fallible) } + #[inline] fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility) -> Result<(), CollectionAllocErr> { @@ -1571,6 +1573,7 @@ impl HashMap /// so that the map now contains keys which compare equal, search may start /// acting erratically, with two keys randomly masking each other. Implementations /// are free to assume this doesn't happen (within the limits of memory-safety). + #[inline(always)] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut { self.reserve(1); @@ -1911,6 +1914,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> } /// Create a `RawEntryMut` from the given key and its hash. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S> where K: Borrow, @@ -1919,6 +1923,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> self.from_hash(hash, |q| q.borrow().eq(k)) } + #[inline] fn search(self, hash: u64, is_match: F, compare_hashes: bool) -> RawEntryMut<'a, K, V, S> where for<'b> F: FnMut(&'b K) -> bool, { @@ -1941,6 +1946,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> } } /// Create a `RawEntryMut` from the given hash. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> where for<'b> F: FnMut(&'b K) -> bool, @@ -2215,6 +2221,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) { let hash = SafeHash::new(hash); diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 547f97cc8acee..479e6dccb90dd 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -329,6 +329,7 @@ impl Put for FullBucket } impl>> Bucket { + #[inline] pub fn new(table: M, hash: SafeHash) -> Bucket { Bucket::at_index(table, hash.inspect() as usize) } @@ -342,6 +343,7 @@ impl>> Bucket { } } + #[inline] pub fn at_index(table: M, ib_index: usize) -> Bucket { // if capacity is 0, then the RawBucket will be populated with bogus pointers. // This is an uncommon case though, so avoid it in release builds. @@ -654,6 +656,7 @@ impl GapThenFull // Returns a Layout which describes the allocation required for a hash table, // and the offset of the array of (key, value) pairs in the allocation. +#[inline(always)] fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { let hashes = Layout::array::(capacity)?; let pairs = Layout::array::<(K, V)>(capacity)?; @@ -722,6 +725,7 @@ impl RawTable { } } + #[inline(always)] fn raw_bucket_at(&self, index: usize) -> RawBucket { let (_, pairs_offset) = calculate_layout::(self.capacity()) .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index a0590a800d3cc..4930d35660814 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -334,9 +334,17 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] -#[inline(never)] #[cold] +#[cold] +// If panic_immediate_abort, inline the abort call, +// otherwise avoid inlining because of it is cold path. +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] +#[cfg_attr( feature="panic_immediate_abort" ,inline)] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { intrinsics::abort() } + } + let (file, line, col) = *file_line_col; let info = PanicInfo::internal_constructor( Some(msg), @@ -398,8 +406,15 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[cfg_attr(not(test), lang = "begin_panic")] -#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible +// never inline unless panic_immediate_abort to avoid code +// bloat at the call sites as much as possible +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] +#[cold] pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { intrinsics::abort() } + } + // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index cc8af70a050c9..68a96293891a0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1201,50 +1201,62 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_expr(&mut self, expr: P) -> P { - let mut expr = self.cfg.configure_expr(expr).into_inner(); - expr.node = self.cfg.configure_expr_kind(expr.node); - - // ignore derives so they remain unused - let (attr, expr, after_derive) = self.classify_nonitem(expr); - - if attr.is_some() { - // collect the invoc regardless of whether or not attributes are permitted here - // expansion will eat the attribute so it won't error later - attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); - - // AstFragmentKind::Expr requires the macro to emit an expression - return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), - AstFragmentKind::Expr, after_derive).make_expr(); - } + let expr = self.cfg.configure_expr(expr); + expr.map(|mut expr| { + expr.node = self.cfg.configure_expr_kind(expr.node); + + // ignore derives so they remain unused + let (attr, expr, after_derive) = self.classify_nonitem(expr); + + if attr.is_some() { + // Collect the invoc regardless of whether or not attributes are permitted here + // expansion will eat the attribute so it won't error later. + attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); + + // AstFragmentKind::Expr requires the macro to emit an expression. + return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), + AstFragmentKind::Expr, after_derive) + .make_expr() + .into_inner() + } - if let ast::ExprKind::Mac(mac) = expr.node { - self.check_attributes(&expr.attrs); - self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr() - } else { - P(noop_fold_expr(expr, self)) - } + if let ast::ExprKind::Mac(mac) = expr.node { + self.check_attributes(&expr.attrs); + self.collect_bang(mac, expr.span, AstFragmentKind::Expr) + .make_expr() + .into_inner() + } else { + noop_fold_expr(expr, self) + } + }) } fn fold_opt_expr(&mut self, expr: P) -> Option> { - let mut expr = configure!(self, expr).into_inner(); - expr.node = self.cfg.configure_expr_kind(expr.node); + let expr = configure!(self, expr); + expr.filter_map(|mut expr| { + expr.node = self.cfg.configure_expr_kind(expr.node); - // ignore derives so they remain unused - let (attr, expr, after_derive) = self.classify_nonitem(expr); + // Ignore derives so they remain unused. + let (attr, expr, after_derive) = self.classify_nonitem(expr); - if attr.is_some() { - attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); + if attr.is_some() { + attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); - return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), - AstFragmentKind::OptExpr, after_derive).make_opt_expr(); - } + return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), + AstFragmentKind::OptExpr, after_derive) + .make_opt_expr() + .map(|expr| expr.into_inner()) + } - if let ast::ExprKind::Mac(mac) = expr.node { - self.check_attributes(&expr.attrs); - self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr).make_opt_expr() - } else { - Some(P(noop_fold_expr(expr, self))) - } + if let ast::ExprKind::Mac(mac) = expr.node { + self.check_attributes(&expr.attrs); + self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) + .make_opt_expr() + .map(|expr| expr.into_inner()) + } else { + Some(noop_fold_expr(expr, self)) + } + }) } fn fold_pat(&mut self, pat: P) -> P { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c93abc39ff3b9..2402de5a816b7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -475,9 +475,6 @@ declare_features! ( // Non-builtin attributes in inner attribute position (active, custom_inner_attributes, "1.30.0", Some(54726), None), - // Self struct constructor (RFC 2302) - (active, self_struct_ctor, "1.30.0", Some(51994), None), - // allow mixing of bind-by-move in patterns and references to // those identifiers in guards, *if* we are using MIR-borrowck // (aka NLL). Essentially this means you need to be on @@ -688,9 +685,11 @@ declare_features! ( (accepted, macro_literal_matcher, "1.31.0", Some(35625), None), // Use `?` as the Kleene "at most one" operator (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), + // Self struct constructor (RFC 2302) + (accepted, self_struct_ctor, "1.32.0", Some(51994), None), ); -// If you change this, please modify src/doc/unstable-book as well. You must +// If you change this, please modify `src/doc/unstable-book` as well. You must // move that documentation into the relevant place in the other docs, and // remove the chapter on the flag. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 506199b60adb6..f13bb7df0b444 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2791,7 +2791,7 @@ impl<'a> Parser<'a> { s.print_usize(float.trunc() as usize)?; s.pclose()?; s.s.word(".")?; - s.s.word(fstr.splitn(2, ".").last().unwrap()) + s.s.word(fstr.splitn(2, ".").last().unwrap().to_string()) }); err.span_suggestion_with_applicability( lo.to(self.prev_span), diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 086de35d531c7..aaed56da29d5f 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -140,13 +140,14 @@ //! calculation, SCAN will write "infinity" to the size and let PRINT consume //! it. //! -//! In this implementation (following the paper, again) the SCAN process is -//! the method called `Printer::pretty_print`, and the 'PRINT' process is the method -//! called `Printer::print`. +//! In this implementation (following the paper, again) the SCAN process is the +//! methods called `Printer::pretty_print_*`, and the 'PRINT' process is the +//! method called `Printer::print`. use std::collections::VecDeque; use std::fmt; use std::io; +use std::borrow::Cow; /// How to break. Described in more detail in the module docs. #[derive(Clone, Copy, PartialEq)] @@ -169,7 +170,10 @@ pub struct BeginToken { #[derive(Clone)] pub enum Token { - String(String, isize), + // In practice a string token contains either a `&'static str` or a + // `String`. `Cow` is overkill for this because we never modify the data, + // but it's more convenient than rolling our own more specialized type. + String(Cow<'static, str>, isize), Break(BreakToken), Begin(BeginToken), End, @@ -309,84 +313,86 @@ impl<'a> Printer<'a> { pub fn last_token(&mut self) -> Token { self.buf[self.right].token.clone() } - /// be very careful with this! + + /// Be very careful with this! pub fn replace_last_token(&mut self, t: Token) { self.buf[self.right].token = t; } - pub fn pretty_print(&mut self, token: Token) -> io::Result<()> { - debug!("pp Vec<{},{}>", self.left, self.right); - match token { - Token::Eof => { - if !self.scan_stack.is_empty() { - self.check_stack(0); - self.advance_left()?; - } - self.indent(0); - Ok(()) - } - Token::Begin(b) => { - if self.scan_stack.is_empty() { - self.left_total = 1; - self.right_total = 1; - self.left = 0; - self.right = 0; - } else { - self.advance_right(); - } - debug!("pp Begin({})/buffer Vec<{},{}>", - b.offset, self.left, self.right); - self.buf[self.right] = BufEntry { token: token, size: -self.right_total }; - let right = self.right; - self.scan_push(right); - Ok(()) - } - Token::End => { - if self.scan_stack.is_empty() { - debug!("pp End/print Vec<{},{}>", self.left, self.right); - self.print(token, 0) - } else { - debug!("pp End/buffer Vec<{},{}>", self.left, self.right); - self.advance_right(); - self.buf[self.right] = BufEntry { token: token, size: -1 }; - let right = self.right; - self.scan_push(right); - Ok(()) - } - } - Token::Break(b) => { - if self.scan_stack.is_empty() { - self.left_total = 1; - self.right_total = 1; - self.left = 0; - self.right = 0; - } else { - self.advance_right(); - } - debug!("pp Break({})/buffer Vec<{},{}>", - b.offset, self.left, self.right); + + fn pretty_print_eof(&mut self) -> io::Result<()> { + if !self.scan_stack.is_empty() { self.check_stack(0); + self.advance_left()?; + } + self.indent(0); + Ok(()) + } + + fn pretty_print_begin(&mut self, b: BeginToken) -> io::Result<()> { + if self.scan_stack.is_empty() { + self.left_total = 1; + self.right_total = 1; + self.left = 0; + self.right = 0; + } else { + self.advance_right(); + } + debug!("pp Begin({})/buffer Vec<{},{}>", + b.offset, self.left, self.right); + self.buf[self.right] = BufEntry { token: Token::Begin(b), size: -self.right_total }; + let right = self.right; + self.scan_push(right); + Ok(()) + } + + fn pretty_print_end(&mut self) -> io::Result<()> { + if self.scan_stack.is_empty() { + debug!("pp End/print Vec<{},{}>", self.left, self.right); + self.print_end() + } else { + debug!("pp End/buffer Vec<{},{}>", self.left, self.right); + self.advance_right(); + self.buf[self.right] = BufEntry { token: Token::End, size: -1 }; let right = self.right; self.scan_push(right); - self.buf[self.right] = BufEntry { token: token, size: -self.right_total }; - self.right_total += b.blank_space; Ok(()) - } - Token::String(s, len) => { - if self.scan_stack.is_empty() { - debug!("pp String('{}')/print Vec<{},{}>", - s, self.left, self.right); - self.print(Token::String(s, len), len) - } else { - debug!("pp String('{}')/buffer Vec<{},{}>", - s, self.left, self.right); - self.advance_right(); - self.buf[self.right] = BufEntry { token: Token::String(s, len), size: len }; - self.right_total += len; - self.check_stream() - } - } } } + + fn pretty_print_break(&mut self, b: BreakToken) -> io::Result<()> { + if self.scan_stack.is_empty() { + self.left_total = 1; + self.right_total = 1; + self.left = 0; + self.right = 0; + } else { + self.advance_right(); + } + debug!("pp Break({})/buffer Vec<{},{}>", + b.offset, self.left, self.right); + self.check_stack(0); + let right = self.right; + self.scan_push(right); + self.buf[self.right] = BufEntry { token: Token::Break(b), size: -self.right_total }; + self.right_total += b.blank_space; + Ok(()) + } + + fn pretty_print_string(&mut self, s: Cow<'static, str>, len: isize) -> io::Result<()> { + if self.scan_stack.is_empty() { + debug!("pp String('{}')/print Vec<{},{}>", + s, self.left, self.right); + self.print_string(s, len) + } else { + debug!("pp String('{}')/buffer Vec<{},{}>", + s, self.left, self.right); + self.advance_right(); + self.buf[self.right] = BufEntry { token: Token::String(s, len), size: len }; + self.right_total += len; + self.check_stream() + } + } + pub fn check_stream(&mut self) -> io::Result<()> { debug!("check_stream Vec<{}, {}> with left_total={}, right_total={}", self.left, self.right, self.left_total, self.right_total); @@ -405,19 +411,24 @@ impl<'a> Printer<'a> { } Ok(()) } + pub fn scan_push(&mut self, x: usize) { debug!("scan_push {}", x); self.scan_stack.push_front(x); } + pub fn scan_pop(&mut self) -> usize { self.scan_stack.pop_front().unwrap() } + pub fn scan_top(&mut self) -> usize { *self.scan_stack.front().unwrap() } + pub fn scan_pop_bottom(&mut self) -> usize { self.scan_stack.pop_back().unwrap() } + pub fn advance_right(&mut self) { self.right += 1; self.right %= self.buf_max_len; @@ -427,6 +438,7 @@ impl<'a> Printer<'a> { } assert_ne!(self.right, self.left); } + pub fn advance_left(&mut self) -> io::Result<()> { debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right, self.left, self.buf[self.left].size); @@ -461,6 +473,7 @@ impl<'a> Printer<'a> { Ok(()) } + pub fn check_stack(&mut self, k: isize) { if !self.scan_stack.is_empty() { let x = self.scan_top(); @@ -488,6 +501,7 @@ impl<'a> Printer<'a> { } } } + pub fn print_newline(&mut self, amount: isize) -> io::Result<()> { debug!("NEWLINE {}", amount); let ret = write!(self.out, "\n"); @@ -495,10 +509,12 @@ impl<'a> Printer<'a> { self.indent(amount); ret } + pub fn indent(&mut self, amount: isize) { debug!("INDENT {}", amount); self.pending_indentation += amount; } + pub fn get_top(&mut self) -> PrintStackElem { match self.print_stack.last() { Some(el) => *el, @@ -508,62 +524,50 @@ impl<'a> Printer<'a> { } } } - pub fn print_str(&mut self, s: &str) -> io::Result<()> { - while self.pending_indentation > 0 { - write!(self.out, " ")?; - self.pending_indentation -= 1; + + pub fn print_begin(&mut self, b: BeginToken, l: isize) -> io::Result<()> { + if l > self.space { + let col = self.margin - self.space + b.offset; + debug!("print Begin -> push broken block at col {}", col); + self.print_stack.push(PrintStackElem { + offset: col, + pbreak: PrintStackBreak::Broken(b.breaks) + }); + } else { + debug!("print Begin -> push fitting block"); + self.print_stack.push(PrintStackElem { + offset: 0, + pbreak: PrintStackBreak::Fits + }); } - write!(self.out, "{}", s) + Ok(()) } - pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> { - debug!("print {} {} (remaining line space={})", token, l, - self.space); - debug!("{}", buf_str(&self.buf, - self.left, - self.right, - 6)); - match token { - Token::Begin(b) => { - if l > self.space { - let col = self.margin - self.space + b.offset; - debug!("print Begin -> push broken block at col {}", col); - self.print_stack.push(PrintStackElem { - offset: col, - pbreak: PrintStackBreak::Broken(b.breaks) - }); - } else { - debug!("print Begin -> push fitting block"); - self.print_stack.push(PrintStackElem { - offset: 0, - pbreak: PrintStackBreak::Fits - }); - } - Ok(()) - } - Token::End => { - debug!("print End -> pop End"); - let print_stack = &mut self.print_stack; - assert!(!print_stack.is_empty()); - print_stack.pop().unwrap(); - Ok(()) - } - Token::Break(b) => { - let top = self.get_top(); - match top.pbreak { - PrintStackBreak::Fits => { + + pub fn print_end(&mut self) -> io::Result<()> { + debug!("print End -> pop End"); + let print_stack = &mut self.print_stack; + assert!(!print_stack.is_empty()); + print_stack.pop().unwrap(); + Ok(()) + } + + pub fn print_break(&mut self, b: BreakToken, l: isize) -> io::Result<()> { + let top = self.get_top(); + match top.pbreak { + PrintStackBreak::Fits => { debug!("print Break({}) in fitting block", b.blank_space); self.space -= b.blank_space; self.indent(b.blank_space); Ok(()) - } - PrintStackBreak::Broken(Breaks::Consistent) => { + } + PrintStackBreak::Broken(Breaks::Consistent) => { debug!("print Break({}+{}) in consistent block", top.offset, b.offset); let ret = self.print_newline(top.offset + b.offset); self.space = self.margin - (top.offset + b.offset); ret - } - PrintStackBreak::Broken(Breaks::Inconsistent) => { + } + PrintStackBreak::Broken(Breaks::Inconsistent) => { if l > self.space { debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset); @@ -577,20 +581,37 @@ impl<'a> Printer<'a> { self.space -= b.blank_space; Ok(()) } - } } - } - Token::String(ref s, len) => { - debug!("print String({})", s); - assert_eq!(l, len); - // assert!(l <= space); - self.space -= len; - self.print_str(s) - } - Token::Eof => { - // Eof should never get here. - panic!(); - } + } + } + + pub fn print_string(&mut self, s: Cow<'static, str>, len: isize) -> io::Result<()> { + debug!("print String({})", s); + // assert!(len <= space); + self.space -= len; + while self.pending_indentation > 0 { + write!(self.out, " ")?; + self.pending_indentation -= 1; + } + write!(self.out, "{}", s) + } + + pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> { + debug!("print {} {} (remaining line space={})", token, l, + self.space); + debug!("{}", buf_str(&self.buf, + self.left, + self.right, + 6)); + match token { + Token::Begin(b) => self.print_begin(b, l), + Token::End => self.print_end(), + Token::Break(b) => self.print_break(b, l), + Token::String(s, len) => { + assert_eq!(len, l); + self.print_string(s, len) + } + Token::Eof => panic!(), // Eof should never get here. } } @@ -598,10 +619,10 @@ impl<'a> Printer<'a> { /// "raw box" pub fn rbox(&mut self, indent: usize, b: Breaks) -> io::Result<()> { - self.pretty_print(Token::Begin(BeginToken { + self.pretty_print_begin(BeginToken { offset: indent as isize, breaks: b - })) + }) } /// Inconsistent breaking box @@ -615,30 +636,24 @@ impl<'a> Printer<'a> { } pub fn break_offset(&mut self, n: usize, off: isize) -> io::Result<()> { - self.pretty_print(Token::Break(BreakToken { + self.pretty_print_break(BreakToken { offset: off, blank_space: n as isize - })) + }) } pub fn end(&mut self) -> io::Result<()> { - self.pretty_print(Token::End) + self.pretty_print_end() } pub fn eof(&mut self) -> io::Result<()> { - self.pretty_print(Token::Eof) - } - - pub fn word(&mut self, wrd: &str) -> io::Result<()> { - self.pretty_print(Token::String(wrd.to_string(), wrd.len() as isize)) - } - - pub fn huge_word(&mut self, wrd: &str) -> io::Result<()> { - self.pretty_print(Token::String(wrd.to_string(), SIZE_INFINITY)) + self.pretty_print_eof() } - pub fn zero_word(&mut self, wrd: &str) -> io::Result<()> { - self.pretty_print(Token::String(wrd.to_string(), 0)) + pub fn word>>(&mut self, wrd: S) -> io::Result<()> { + let s = wrd.into(); + let len = s.len() as isize; + self.pretty_print_string(s, len) } fn spaces(&mut self, n: usize) -> io::Result<()> { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ce7708cc42e56..14ad4b5c6f815 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -29,6 +29,7 @@ use syntax_pos::{DUMMY_SP, FileName}; use tokenstream::{self, TokenStream, TokenTree}; use std::ascii; +use std::borrow::Cow; use std::io::{self, Write, Read}; use std::iter::Peekable; use std::vec; @@ -444,7 +445,7 @@ pub trait PrintState<'a> { fn cur_lit(&mut self) -> Option<&comments::Literal>; fn bump_lit(&mut self) -> Option; - fn word_space(&mut self, w: &str) -> io::Result<()> { + fn word_space>>(&mut self, w: S) -> io::Result<()> { self.writer().word(w)?; self.writer().space() } @@ -539,7 +540,7 @@ pub trait PrintState<'a> { comments::Mixed => { assert_eq!(cmnt.lines.len(), 1); self.writer().zerobreak()?; - self.writer().word(&cmnt.lines[0])?; + self.writer().word(cmnt.lines[0].clone())?; self.writer().zerobreak() } comments::Isolated => { @@ -548,7 +549,7 @@ pub trait PrintState<'a> { // Don't print empty lines because they will end up as trailing // whitespace if !line.is_empty() { - self.writer().word(&line[..])?; + self.writer().word(line.clone())?; } self.writer().hardbreak()?; } @@ -559,13 +560,13 @@ pub trait PrintState<'a> { self.writer().word(" ")?; } if cmnt.lines.len() == 1 { - self.writer().word(&cmnt.lines[0])?; + self.writer().word(cmnt.lines[0].clone())?; self.writer().hardbreak() } else { self.ibox(0)?; for line in &cmnt.lines { if !line.is_empty() { - self.writer().word(&line[..])?; + self.writer().word(line.clone())?; } self.writer().hardbreak()?; } @@ -610,7 +611,7 @@ pub trait PrintState<'a> { fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> { self.maybe_print_comment(lit.span.lo())?; if let Some(ltrl) = self.next_lit(lit.span.lo()) { - return self.writer().word(<rl.lit); + return self.writer().word(ltrl.lit.clone()); } match lit.node { ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style), @@ -618,31 +619,31 @@ pub trait PrintState<'a> { let mut res = String::from("b'"); res.extend(ascii::escape_default(byte).map(|c| c as char)); res.push('\''); - self.writer().word(&res[..]) + self.writer().word(res) } ast::LitKind::Char(ch) => { let mut res = String::from("'"); res.extend(ch.escape_default()); res.push('\''); - self.writer().word(&res[..]) + self.writer().word(res) } ast::LitKind::Int(i, t) => { match t { ast::LitIntType::Signed(st) => { - self.writer().word(&st.val_to_string(i as i128)) + self.writer().word(st.val_to_string(i as i128)) } ast::LitIntType::Unsigned(ut) => { - self.writer().word(&ut.val_to_string(i)) + self.writer().word(ut.val_to_string(i)) } ast::LitIntType::Unsuffixed => { - self.writer().word(&i.to_string()) + self.writer().word(i.to_string()) } } } ast::LitKind::Float(ref f, t) => { - self.writer().word(&format!("{}{}", &f, t.ty_to_string())) + self.writer().word(format!("{}{}", &f, t.ty_to_string())) } - ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(&f.as_str()), + ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(f.as_str().get()), ast::LitKind::Bool(val) => { if val { self.writer().word("true") } else { self.writer().word("false") } } @@ -652,7 +653,7 @@ pub trait PrintState<'a> { escaped.extend(ascii::escape_default(ch) .map(|c| c as char)); } - self.writer().word(&format!("b\"{}\"", escaped)) + self.writer().word(format!("b\"{}\"", escaped)) } } } @@ -669,7 +670,7 @@ pub trait PrintState<'a> { string=st)) } }; - self.writer().word(&st[..]) + self.writer().word(st) } fn print_inner_attributes(&mut self, @@ -727,7 +728,7 @@ pub trait PrintState<'a> { if segment.ident.name != keywords::CrateRoot.name() && segment.ident.name != keywords::DollarCrate.name() { - self.writer().word(&segment.ident.as_str())?; + self.writer().word(segment.ident.as_str().get())?; } else if segment.ident.name == keywords::DollarCrate.name() { self.print_dollar_crate(segment.ident.span.ctxt())?; } @@ -746,7 +747,7 @@ pub trait PrintState<'a> { } self.maybe_print_comment(attr.span.lo())?; if attr.is_sugared_doc { - self.writer().word(&attr.value_str().unwrap().as_str())?; + self.writer().word(attr.value_str().unwrap().as_str().get())?; self.writer().hardbreak() } else { match attr.style { @@ -807,7 +808,7 @@ pub trait PrintState<'a> { fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { match tt { TokenTree::Token(_, ref tk) => { - self.writer().word(&token_to_string(tk))?; + self.writer().word(token_to_string(tk))?; match *tk { parse::token::DocComment(..) => { self.writer().hardbreak() @@ -816,11 +817,11 @@ pub trait PrintState<'a> { } } TokenTree::Delimited(_, ref delimed) => { - self.writer().word(&token_to_string(&delimed.open_token()))?; + self.writer().word(token_to_string(&delimed.open_token()))?; self.writer().space()?; self.print_tts(delimed.stream())?; self.writer().space()?; - self.writer().word(&token_to_string(&delimed.close_token())) + self.writer().word(token_to_string(&delimed.close_token())) }, } } @@ -889,12 +890,13 @@ impl<'a> State<'a> { self.s.cbox(u) } - pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> { + pub fn word_nbsp>>(&mut self, w: S) -> io::Result<()> { self.s.word(w)?; self.nbsp() } - pub fn head(&mut self, w: &str) -> io::Result<()> { + pub fn head>>(&mut self, w: S) -> io::Result<()> { + let w = w.into(); // outer-box is consistent self.cbox(INDENT_UNIT)?; // head-box is inconsistent @@ -956,7 +958,7 @@ impl<'a> State<'a> { pub fn synth_comment(&mut self, text: String) -> io::Result<()> { self.s.word("/*")?; self.s.space()?; - self.s.word(&text[..])?; + self.s.word(text)?; self.s.space()?; self.s.word("*/") } @@ -1129,7 +1131,7 @@ impl<'a> State<'a> { self.end() // end the outer fn box } ast::ForeignItemKind::Static(ref t, m) => { - self.head(&visibility_qualified(&item.vis, "static"))?; + self.head(visibility_qualified(&item.vis, "static"))?; if m { self.word_space("mut")?; } @@ -1141,7 +1143,7 @@ impl<'a> State<'a> { self.end() // end the outer cbox } ast::ForeignItemKind::Ty => { - self.head(&visibility_qualified(&item.vis, "type"))?; + self.head(visibility_qualified(&item.vis, "type"))?; self.print_ident(item.ident)?; self.s.word(";")?; self.end()?; // end the head-ibox @@ -1164,7 +1166,7 @@ impl<'a> State<'a> { vis: &ast::Visibility) -> io::Result<()> { - self.s.word(&visibility_qualified(vis, ""))?; + self.s.word(visibility_qualified(vis, ""))?; self.word_space("const")?; self.print_ident(ident)?; self.word_space(":")?; @@ -1203,7 +1205,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Item(item))?; match item.node { ast::ItemKind::ExternCrate(orig_name) => { - self.head(&visibility_qualified(&item.vis, "extern crate"))?; + self.head(visibility_qualified(&item.vis, "extern crate"))?; if let Some(orig_name) = orig_name { self.print_name(orig_name)?; self.s.space()?; @@ -1216,14 +1218,14 @@ impl<'a> State<'a> { self.end()?; // end outer head-block } ast::ItemKind::Use(ref tree) => { - self.head(&visibility_qualified(&item.vis, "use"))?; + self.head(visibility_qualified(&item.vis, "use"))?; self.print_use_tree(tree)?; self.s.word(";")?; self.end()?; // end inner head-block self.end()?; // end outer head-block } ast::ItemKind::Static(ref ty, m, ref expr) => { - self.head(&visibility_qualified(&item.vis, "static"))?; + self.head(visibility_qualified(&item.vis, "static"))?; if m == ast::Mutability::Mutable { self.word_space("mut")?; } @@ -1239,7 +1241,7 @@ impl<'a> State<'a> { self.end()?; // end the outer cbox } ast::ItemKind::Const(ref ty, ref expr) => { - self.head(&visibility_qualified(&item.vis, "const"))?; + self.head(visibility_qualified(&item.vis, "const"))?; self.print_ident(item.ident)?; self.word_space(":")?; self.print_type(ty)?; @@ -1264,7 +1266,7 @@ impl<'a> State<'a> { self.print_block_with_attrs(body, &item.attrs)?; } ast::ItemKind::Mod(ref _mod) => { - self.head(&visibility_qualified(&item.vis, "mod"))?; + self.head(visibility_qualified(&item.vis, "mod"))?; self.print_ident(item.ident)?; if _mod.inline || self.is_expanded { @@ -1281,18 +1283,18 @@ impl<'a> State<'a> { } ast::ItemKind::ForeignMod(ref nmod) => { self.head("extern")?; - self.word_nbsp(&nmod.abi.to_string())?; + self.word_nbsp(nmod.abi.to_string())?; self.bopen()?; self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } ast::ItemKind::GlobalAsm(ref ga) => { - self.head(&visibility_qualified(&item.vis, "global_asm!"))?; - self.s.word(&ga.asm.as_str())?; + self.head(visibility_qualified(&item.vis, "global_asm!"))?; + self.s.word(ga.asm.as_str().get())?; self.end()?; } ast::ItemKind::Ty(ref ty, ref generics) => { - self.head(&visibility_qualified(&item.vis, "type"))?; + self.head(visibility_qualified(&item.vis, "type"))?; self.print_ident(item.ident)?; self.print_generic_params(&generics.params)?; self.end()?; // end the inner ibox @@ -1305,7 +1307,7 @@ impl<'a> State<'a> { self.end()?; // end the outer ibox } ast::ItemKind::Existential(ref bounds, ref generics) => { - self.head(&visibility_qualified(&item.vis, "existential type"))?; + self.head(visibility_qualified(&item.vis, "existential type"))?; self.print_ident(item.ident)?; self.print_generic_params(&generics.params)?; self.end()?; // end the inner ibox @@ -1326,11 +1328,11 @@ impl<'a> State<'a> { )?; } ast::ItemKind::Struct(ref struct_def, ref generics) => { - self.head(&visibility_qualified(&item.vis, "struct"))?; + self.head(visibility_qualified(&item.vis, "struct"))?; self.print_struct(struct_def, generics, item.ident, item.span, true)?; } ast::ItemKind::Union(ref struct_def, ref generics) => { - self.head(&visibility_qualified(&item.vis, "union"))?; + self.head(visibility_qualified(&item.vis, "union"))?; self.print_struct(struct_def, generics, item.ident, item.span, true)?; } ast::ItemKind::Impl(unsafety, @@ -1479,7 +1481,7 @@ impl<'a> State<'a> { generics: &ast::Generics, ident: ast::Ident, span: syntax_pos::Span, visibility: &ast::Visibility) -> io::Result<()> { - self.head(&visibility_qualified(visibility, "enum"))?; + self.head(visibility_qualified(visibility, "enum"))?; self.print_ident(ident)?; self.print_generic_params(&generics.params)?; self.print_where_clause(&generics.where_clause)?; @@ -1514,9 +1516,9 @@ impl<'a> State<'a> { ast::VisibilityKind::Restricted { ref path, .. } => { let path = to_string(|s| s.print_path(path, false, 0)); if path == "self" || path == "super" { - self.word_nbsp(&format!("pub({})", path)) + self.word_nbsp(format!("pub({})", path)) } else { - self.word_nbsp(&format!("pub(in {})", path)) + self.word_nbsp(format!("pub(in {})", path)) } } ast::VisibilityKind::Inherited => Ok(()) @@ -2415,19 +2417,19 @@ impl<'a> State<'a> { pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> { if ident.is_raw_guess() { - self.s.word(&format!("r#{}", ident))?; + self.s.word(format!("r#{}", ident))?; } else { - self.s.word(&ident.as_str())?; + self.s.word(ident.as_str().get())?; } self.ann.post(self, AnnNode::Ident(&ident)) } pub fn print_usize(&mut self, i: usize) -> io::Result<()> { - self.s.word(&i.to_string()) + self.s.word(i.to_string()) } pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> { - self.s.word(&name.as_str())?; + self.s.word(name.as_str().get())?; self.ann.post(self, AnnNode::Name(&name)) } @@ -2851,10 +2853,8 @@ impl<'a> State<'a> { } } - pub fn print_type_bounds(&mut self, - prefix: &str, - bounds: &[ast::GenericBound]) - -> io::Result<()> { + pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) + -> io::Result<()> { if !bounds.is_empty() { self.s.word(prefix)?; let mut first = true; @@ -3146,7 +3146,7 @@ impl<'a> State<'a> { Some(Abi::Rust) => Ok(()), Some(abi) => { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string()) + self.word_nbsp(abi.to_string()) } None => Ok(()) } @@ -3157,7 +3157,7 @@ impl<'a> State<'a> { match opt_abi { Some(abi) => { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string()) + self.word_nbsp(abi.to_string()) } None => Ok(()) } @@ -3166,7 +3166,7 @@ impl<'a> State<'a> { pub fn print_fn_header_info(&mut self, header: ast::FnHeader, vis: &ast::Visibility) -> io::Result<()> { - self.s.word(&visibility_qualified(vis, ""))?; + self.s.word(visibility_qualified(vis, ""))?; match header.constness.node { ast::Constness::NotConst => {} @@ -3178,7 +3178,7 @@ impl<'a> State<'a> { if header.abi != Abi::Rust { self.word_nbsp("extern")?; - self.word_nbsp(&header.abi.to_string())?; + self.word_nbsp(header.abi.to_string())?; } self.s.word("fn") diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index bb47d9b535bef..9fbc64758da4d 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -72,7 +72,7 @@ impl P { *self.ptr } - /// Transform the inner value, consuming `self` and producing a new `P`. + /// Produce a new `P` from `self` without reallocating. pub fn map(mut self, f: F) -> P where F: FnOnce(T) -> T, { @@ -88,8 +88,30 @@ impl P { ptr::write(p, f(ptr::read(p))); // Recreate self from the raw pointer. - P { - ptr: Box::from_raw(p) + P { ptr: Box::from_raw(p) } + } + } + + /// Optionally produce a new `P` from `self` without reallocating. + pub fn filter_map(mut self, f: F) -> Option> where + F: FnOnce(T) -> Option, + { + let p: *mut T = &mut *self.ptr; + + // Leak self in case of panic. + // FIXME(eddyb) Use some sort of "free guard" that + // only deallocates, without dropping the pointee, + // in case the call the `f` below ends in a panic. + mem::forget(self); + + unsafe { + if let Some(v) = f(ptr::read(p)) { + ptr::write(p, v); + + // Recreate self from the raw pointer. + Some(P { ptr: Box::from_raw(p) }) + } else { + None } } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 65f6d27239b83..34fb71e4ddf68 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -587,6 +587,7 @@ impl fmt::Debug for SpanData { } impl MultiSpan { + #[inline] pub fn new() -> MultiSpan { MultiSpan { primary_spans: vec![], diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index e333a4f2176f5..741877bb4c88f 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -492,6 +492,10 @@ impl LocalInternedString { symbol: Symbol::intern(self.string) } } + + pub fn get(&self) -> &'static str { + self.string + } } impl ::std::convert::AsRef for LocalInternedString diff --git a/src/test/run-make/llvm-outputs/Makefile b/src/test/run-make/llvm-outputs/Makefile new file mode 100644 index 0000000000000..d7f67577b04ce --- /dev/null +++ b/src/test/run-make/llvm-outputs/Makefile @@ -0,0 +1,5 @@ +-include ../../run-make-fulldeps/tools.mk + +all: + echo 'fn main() {}' | $(BARE_RUSTC) - --out-dir=$(TMPDIR)/random_directory_that_does_not_exist_ir/ --emit=llvm-ir + echo 'fn main() {}' | $(BARE_RUSTC) - --out-dir=$(TMPDIR)/random_directory_that_does_not_exist_bc/ --emit=llvm-bc diff --git a/src/test/run-pass/rfcs/rfc-2302-self-struct-ctor.rs b/src/test/run-pass/rfcs/rfc-2302-self-struct-ctor.rs index 156e240e44282..1ec20c50034bd 100644 --- a/src/test/run-pass/rfcs/rfc-2302-self-struct-ctor.rs +++ b/src/test/run-pass/rfcs/rfc-2302-self-struct-ctor.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(self_struct_ctor)] - #![allow(dead_code)] use std::fmt::Display; diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs new file mode 100644 index 0000000000000..9d1a8b59463e7 --- /dev/null +++ b/src/test/ui/consts/issue-56164.rs @@ -0,0 +1,13 @@ +#![feature(const_fn)] + +const fn foo() { (||{})() } +//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple +// variants + +const fn bad(input: fn()) { + input() + //~^ ERROR function pointers are not allowed in const fn +} + +fn main() { +} diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr new file mode 100644 index 0000000000000..d3e9ce379aed7 --- /dev/null +++ b/src/test/ui/consts/issue-56164.stderr @@ -0,0 +1,15 @@ +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-56164.rs:3:18 + | +LL | const fn foo() { (||{})() } + | ^^^^^^^^ + +error: function pointers are not allowed in const fn + --> $DIR/issue-56164.rs:8:5 + | +LL | input() + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/feature-gate-custom_test_frameworks.rs b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs similarity index 100% rename from src/test/ui/feature-gate-custom_test_frameworks.rs rename to src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs diff --git a/src/test/ui/feature-gate-custom_test_frameworks.stderr b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr similarity index 100% rename from src/test/ui/feature-gate-custom_test_frameworks.stderr rename to src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr diff --git a/src/test/ui/feature-gate-doc_cfg-cfg-rustdoc.rs b/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.rs similarity index 100% rename from src/test/ui/feature-gate-doc_cfg-cfg-rustdoc.rs rename to src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.rs diff --git a/src/test/ui/feature-gate-doc_cfg-cfg-rustdoc.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr similarity index 100% rename from src/test/ui/feature-gate-doc_cfg-cfg-rustdoc.stderr rename to src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr diff --git a/src/test/ui/feature-gates/feature-gate-self-struct-ctor.rs b/src/test/ui/feature-gates/feature-gate-self-struct-ctor.rs deleted file mode 100644 index 98eab39491320..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-self-struct-ctor.rs +++ /dev/null @@ -1,22 +0,0 @@ -struct ST1(i32, i32); - -impl ST1 { - fn ctor() -> Self { - Self(1,2) - //~^ ERROR: `Self` struct constructors are unstable (see issue #51994) [E0658] - } -} - -struct ST2; - -impl ST2 { - fn ctor() -> Self { - Self - //~^ ERROR: `Self` struct constructors are unstable (see issue #51994) [E0658] - } -} - -fn main() { - let _ = ST1::ctor(); - let _ = ST2::ctor(); -} diff --git a/src/test/ui/feature-gates/feature-gate-self-struct-ctor.stderr b/src/test/ui/feature-gates/feature-gate-self-struct-ctor.stderr deleted file mode 100644 index 6061a0db76ec5..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-self-struct-ctor.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: `Self` struct constructors are unstable (see issue #51994) - --> $DIR/feature-gate-self-struct-ctor.rs:5:9 - | -LL | Self(1,2) - | ^^^^ - | - = help: add #![feature(self_struct_ctor)] to the crate attributes to enable - -error[E0658]: `Self` struct constructors are unstable (see issue #51994) - --> $DIR/feature-gate-self-struct-ctor.rs:14:9 - | -LL | Self - | ^^^^ - | - = help: add #![feature(self_struct_ctor)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-underscore_const_names.rs b/src/test/ui/feature-gates/feature-gate-underscore_const_names.rs similarity index 100% rename from src/test/ui/feature-gate-underscore_const_names.rs rename to src/test/ui/feature-gates/feature-gate-underscore_const_names.rs diff --git a/src/test/ui/feature-gate-underscore_const_names.stderr b/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr similarity index 100% rename from src/test/ui/feature-gate-underscore_const_names.stderr rename to src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr diff --git a/src/test/ui/feature-gate-unsized_locals.rs b/src/test/ui/feature-gates/feature-gate-unsized_locals.rs similarity index 100% rename from src/test/ui/feature-gate-unsized_locals.rs rename to src/test/ui/feature-gates/feature-gate-unsized_locals.rs diff --git a/src/test/ui/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr similarity index 100% rename from src/test/ui/feature-gate-unsized_locals.stderr rename to src/test/ui/feature-gates/feature-gate-unsized_locals.stderr diff --git a/src/test/ui/issues/issue-56202.rs b/src/test/ui/issues/issue-56202.rs new file mode 100644 index 0000000000000..bd222b7fe980e --- /dev/null +++ b/src/test/ui/issues/issue-56202.rs @@ -0,0 +1,17 @@ +// compile-pass + +trait FooTrait {} + +trait BarTrait { + fn foo(_: T) -> Self; +} + +struct FooStruct(u32); + +impl BarTrait for FooStruct { + fn foo(_: T) -> Self { + Self(u32::default()) + } +} + +fn main() {} diff --git a/src/test/ui/keyword/keyword-self-as-identifier.rs b/src/test/ui/keyword/keyword-self-as-identifier.rs index ad5b8fb64342d..b50fc68bed6be 100644 --- a/src/test/ui/keyword/keyword-self-as-identifier.rs +++ b/src/test/ui/keyword/keyword-self-as-identifier.rs @@ -10,5 +10,4 @@ fn main() { let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope - //~^ ERROR `Self` struct constructors are unstable (see issue #51994) } diff --git a/src/test/ui/keyword/keyword-self-as-identifier.stderr b/src/test/ui/keyword/keyword-self-as-identifier.stderr index 296269819f836..c47f4aeabefd8 100644 --- a/src/test/ui/keyword/keyword-self-as-identifier.stderr +++ b/src/test/ui/keyword/keyword-self-as-identifier.stderr @@ -4,15 +4,6 @@ error[E0531]: cannot find unit struct/variant or constant `Self` in this scope LL | let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope | ^^^^ not found in this scope -error[E0658]: `Self` struct constructors are unstable (see issue #51994) - --> $DIR/keyword-self-as-identifier.rs:12:9 - | -LL | let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope - | ^^^^ - | - = help: add #![feature(self_struct_ctor)] to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0531, E0658. -For more information about an error, try `rustc --explain E0531`. +For more information about this error, try `rustc --explain E0531`. diff --git a/src/test/ui/self/self_type_keyword-2.rs b/src/test/ui/self/self_type_keyword-2.rs index bbaf060ca87e3..8331ae0b307d9 100644 --- a/src/test/ui/self/self_type_keyword-2.rs +++ b/src/test/ui/self/self_type_keyword-2.rs @@ -13,14 +13,11 @@ use self::Self as Foo; //~ ERROR unresolved import `self::Self` pub fn main() { let Self = 5; //~^ ERROR cannot find unit struct/variant or constant `Self` in this scope - //~^^ ERROR `Self` struct constructors are unstable (see issue #51994) match 15 { Self => (), //~^ ERROR cannot find unit struct/variant or constant `Self` in this scope - //~^^ ERROR `Self` struct constructors are unstable (see issue #51994) Foo { x: Self } => (), //~^ ERROR cannot find unit struct/variant or constant `Self` in this scope - //~^^ ERROR `Self` struct constructors are unstable (see issue #51994) } } diff --git a/src/test/ui/self/self_type_keyword-2.stderr b/src/test/ui/self/self_type_keyword-2.stderr index 82529974d0e37..972e5bdddc673 100644 --- a/src/test/ui/self/self_type_keyword-2.stderr +++ b/src/test/ui/self/self_type_keyword-2.stderr @@ -11,42 +11,18 @@ LL | let Self = 5; | ^^^^ not found in this scope error[E0531]: cannot find unit struct/variant or constant `Self` in this scope - --> $DIR/self_type_keyword-2.rs:19:9 + --> $DIR/self_type_keyword-2.rs:18:9 | LL | Self => (), | ^^^^ not found in this scope error[E0531]: cannot find unit struct/variant or constant `Self` in this scope - --> $DIR/self_type_keyword-2.rs:22:18 + --> $DIR/self_type_keyword-2.rs:20:18 | LL | Foo { x: Self } => (), | ^^^^ not found in this scope -error[E0658]: `Self` struct constructors are unstable (see issue #51994) - --> $DIR/self_type_keyword-2.rs:14:9 - | -LL | let Self = 5; - | ^^^^ - | - = help: add #![feature(self_struct_ctor)] to the crate attributes to enable - -error[E0658]: `Self` struct constructors are unstable (see issue #51994) - --> $DIR/self_type_keyword-2.rs:19:9 - | -LL | Self => (), - | ^^^^ - | - = help: add #![feature(self_struct_ctor)] to the crate attributes to enable - -error[E0658]: `Self` struct constructors are unstable (see issue #51994) - --> $DIR/self_type_keyword-2.rs:22:18 - | -LL | Foo { x: Self } => (), - | ^^^^ - | - = help: add #![feature(self_struct_ctor)] to the crate attributes to enable - -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors -Some errors occurred: E0432, E0531, E0658. +Some errors occurred: E0432, E0531. For more information about an error, try `rustc --explain E0432`. diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index ca7e0224dc328..11c83819eaa93 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -24,12 +24,12 @@ //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc, //! but this should catch the majority of "broken link" cases. +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; use std::env; -use std::fs::File; -use std::io::prelude::*; +use std::fs; use std::path::{Path, PathBuf, Component}; -use std::collections::{HashMap, HashSet}; -use std::collections::hash_map::Entry; +use std::rc::Rc; use Redirect::*; @@ -63,7 +63,7 @@ enum Redirect { } struct FileEntry { - source: String, + source: Rc, ids: HashSet, } @@ -113,7 +113,7 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { let entry = cache.get_mut(&pretty_path).unwrap(); // we don't need the source anymore, // so drop to reduce memory-usage - entry.source = String::new(); + entry.source = Rc::new(String::new()); } } } @@ -287,24 +287,24 @@ fn load_file(cache: &mut Cache, root: &Path, file: &Path, redirect: Redirect) - -> Result<(PathBuf, String), LoadError> { - let mut contents = String::new(); + -> Result<(PathBuf, Rc), LoadError> { let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file)); - let maybe_redirect = match cache.entry(pretty_file.clone()) { + let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) { Entry::Occupied(entry) => { - contents = entry.get().source.clone(); - None + (None, entry.get().source.clone()) } Entry::Vacant(entry) => { - let mut fp = File::open(file).map_err(|err| { - if let FromRedirect(true) = redirect { - LoadError::BrokenRedirect(file.to_path_buf(), err) - } else { - LoadError::IOError(err) + let contents = match fs::read_to_string(file) { + Ok(s) => Rc::new(s), + Err(err) => { + return Err(if let FromRedirect(true) = redirect { + LoadError::BrokenRedirect(file.to_path_buf(), err) + } else { + LoadError::IOError(err) + }) } - })?; - fp.read_to_string(&mut contents).map_err(|err| LoadError::IOError(err))?; + }; let maybe = maybe_redirect(&contents); if maybe.is_some() { @@ -317,7 +317,7 @@ fn load_file(cache: &mut Cache, ids: HashSet::new(), }); } - maybe + (maybe, contents) } }; match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {