diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5790f236cc8fd..21dcb1d8aa0e1 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -262,7 +262,7 @@ impl Step for Llvm { cfg.define("PYTHON_EXECUTABLE", python); } - configure_cmake(builder, target, &mut cfg); + configure_cmake(builder, target, &mut cfg, true); // FIXME: we don't actually need to build all LLVM tools and all LLVM // libraries here, e.g., we just want a few components and a few @@ -301,7 +301,12 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { panic!("\n\nbad LLVM version: {}, need >=7.0\n\n", version) } -fn configure_cmake(builder: &Builder<'_>, target: Interned, cfg: &mut cmake::Config) { +fn configure_cmake( + builder: &Builder<'_>, + target: Interned, + cfg: &mut cmake::Config, + use_compiler_launcher: bool, +) { // Do not print installation messages for up-to-date files. // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY"); @@ -372,9 +377,11 @@ fn configure_cmake(builder: &Builder<'_>, target: Interned, cfg: &mut cm } else { // If ccache is configured we inform the build a little differently how // to invoke ccache while also invoking our compilers. - if let Some(ref ccache) = builder.config.ccache { - cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache) - .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache); + if use_compiler_launcher { + if let Some(ref ccache) = builder.config.ccache { + cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache) + .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache); + } } cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc)) .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx)); @@ -458,7 +465,7 @@ impl Step for Lld { t!(fs::create_dir_all(&out_dir)); let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld")); - configure_cmake(builder, target, &mut cfg); + configure_cmake(builder, target, &mut cfg, true); // This is an awful, awful hack. Discovered when we migrated to using // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of @@ -595,10 +602,7 @@ impl Step for Sanitizers { let _time = util::timeit(&builder); let mut cfg = cmake::Config::new(&compiler_rt_dir); - cfg.target(&self.target); - cfg.host(&builder.config.build); cfg.profile("Release"); - cfg.define("CMAKE_C_COMPILER_TARGET", self.target); cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF"); cfg.define("COMPILER_RT_BUILD_CRT", "OFF"); @@ -610,6 +614,12 @@ impl Step for Sanitizers { cfg.define("COMPILER_RT_USE_LIBCXX", "OFF"); cfg.define("LLVM_CONFIG_PATH", &llvm_config); + // On Darwin targets the sanitizer runtimes are build as universal binaries. + // Unfortunately sccache currently lacks support to build them successfully. + // Disable compiler launcher on Darwin targets to avoid potential issues. + let use_compiler_launcher = !self.target.contains("apple-darwin"); + configure_cmake(builder, self.target, &mut cfg, use_compiler_launcher); + t!(fs::create_dir_all(&out_dir)); cfg.out_dir(out_dir); diff --git a/src/etc/installer/gfx/rust-logo.png b/src/etc/installer/gfx/rust-logo.png index 2c3de3000879b..99ee7507fa2fb 100644 Binary files a/src/etc/installer/gfx/rust-logo.png and b/src/etc/installer/gfx/rust-logo.png differ diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index b4b595f330e22..2800f11cc01b1 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -727,6 +727,10 @@ unsafe impl Freeze for &mut T {} /// [`Pin

`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] +#[rustc_on_unimplemented( + on(_Self = "std::future::Future", note = "consider using `Box::pin`",), + message = "`{Self}` cannot be unpinned" +)] #[lang = "unpin"] pub auto trait Unpin {} diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 2ba12baaf6d6e..ab2d74b1c8deb 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -201,6 +201,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } + if let ty::Dynamic(traits, _) = self_ty.kind { + for t in *traits.skip_binder() { + match t { + ty::ExistentialPredicate::Trait(trait_ref) => { + flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) + } + _ => {} + } + } + } if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index 60e55bd7bd9ad..82b73518d09a8 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -701,10 +701,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) .collect::>(); // Add the suggestion for the return type. - suggestions.push(( - ret_ty.span, - format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet), - )); + suggestions.push((ret_ty.span, format!("Box", trait_obj))); err.multipart_suggestion( "return a boxed trait object instead", suggestions, diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index 4fe7c268c4f0b..f119c956ced04 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -1,3 +1,4 @@ +#![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(proc_macro_diagnostic)] diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index b14725fd731b1..5bf7602ea6e8f 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -78,13 +78,11 @@ use crate::mbe::{self, TokenTree}; use rustc_ast_pretty::pprust; use rustc_parse::parser::{FollowedByType, Parser, PathStyle}; -use rustc_parse::Directory; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Symbol}; use syntax::ast::{Ident, Name}; use syntax::ptr::P; use syntax::token::{self, DocComment, Nonterminal, Token}; -use syntax::tokenstream::TokenStream; use rustc_errors::{FatalError, PResult}; use rustc_span::Span; @@ -92,6 +90,7 @@ use smallvec::{smallvec, SmallVec}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use std::borrow::Cow; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::mem; use std::ops::{Deref, DerefMut}; @@ -613,28 +612,9 @@ fn inner_parse_loop<'root, 'tt>( Success(()) } -/// Use the given sequence of token trees (`ms`) as a matcher. Match the given token stream `tts` -/// against it and return the match. -/// -/// # Parameters -/// -/// - `sess`: The session into which errors are emitted -/// - `tts`: The tokenstream we are matching against the pattern `ms` -/// - `ms`: A sequence of token trees representing a pattern against which we are matching -/// - `directory`: Information about the file locations (needed for the black-box parser) -/// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box -/// parser) -pub(super) fn parse( - sess: &ParseSess, - tts: TokenStream, - ms: &[TokenTree], - directory: Option>, - recurse_into_modules: bool, -) -> NamedParseResult { - // Create a parser that can be used for the "black box" parts. - let mut parser = - Parser::new(sess, tts, directory, recurse_into_modules, true, rustc_parse::MACRO_ARGUMENTS); - +/// Use the given sequence of token trees (`ms`) as a matcher. Match the token +/// stream from the given `parser` against it and return the match. +pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> NamedParseResult { // A queue of possible matcher positions. We initialize it with the matcher position in which // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then // processes all of these possible matcher positions and produces possible next positions into @@ -659,7 +639,7 @@ pub(super) fn parse( // parsing from the black-box parser done. The result is that `next_items` will contain a // bunch of possible next matcher positions in `next_items`. match inner_parse_loop( - sess, + parser.sess, &mut cur_items, &mut next_items, &mut eof_items, @@ -684,7 +664,7 @@ pub(super) fn parse( if eof_items.len() == 1 { let matches = eof_items[0].matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap()); - return nameize(sess, ms, matches); + return nameize(parser.sess, ms, matches); } else if eof_items.len() > 1 { return Error( parser.token.span, @@ -709,9 +689,14 @@ pub(super) fn parse( // unnecessary implicit clone later in Rc::make_mut. drop(eof_items); + // If there are no possible next positions AND we aren't waiting for the black-box parser, + // then there is a syntax error. + if bb_items.is_empty() && next_items.is_empty() { + return Failure(parser.token.clone(), "no rules expected this token in macro call"); + } // Another possibility is that we need to call out to parse some rust nonterminal // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong. - if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 { + else if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 { let nts = bb_items .iter() .map(|item| match item.top_elts.get_tt(item.idx) { @@ -733,16 +718,11 @@ pub(super) fn parse( ), ); } - // If there are no possible next positions AND we aren't waiting for the black-box parser, - // then there is a syntax error. - else if bb_items.is_empty() && next_items.is_empty() { - return Failure(parser.token.take(), "no rules expected this token in macro call"); - } // Dump all possible `next_items` into `cur_items` for the next iteration. else if !next_items.is_empty() { // Now process the next token cur_items.extend(next_items.drain(..)); - parser.bump(); + parser.to_mut().bump(); } // Finally, we have the case where we need to call the black-box parser to get some // nonterminal. @@ -754,7 +734,7 @@ pub(super) fn parse( let match_cur = item.match_cur; item.push_match( match_cur, - MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, ident.name))), + MatchedNonterminal(Lrc::new(parse_nt(parser.to_mut(), span, ident.name))), ); item.idx += 1; item.match_cur += 1; diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 29d41543fbf8c..9e6edee265c98 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -1,11 +1,11 @@ -use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; +use crate::base::{DummyResult, ExpansionData, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::mbe; use crate::mbe::macro_check; -use crate::mbe::macro_parser::parse; +use crate::mbe::macro_parser::parse_tt; use crate::mbe::macro_parser::{Error, Failure, Success}; -use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult}; +use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq}; use crate::mbe::transcribe::transcribe; use rustc_ast_pretty::pprust; @@ -166,9 +166,9 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } -fn trace_macros_note(cx: &mut ExtCtxt<'_>, sp: Span, message: String) { +fn trace_macros_note(cx_expansions: &mut FxHashMap>, sp: Span, message: String) { let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); - cx.expansions.entry(sp).or_default().push(message); + cx_expansions.entry(sp).or_default().push(message); } /// Given `lhses` and `rhses`, this is the new macro we create @@ -184,12 +184,36 @@ fn generic_extension<'cx>( ) -> Box { if cx.trace_macros() { let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); - trace_macros_note(cx, sp, msg); + trace_macros_note(&mut cx.expansions, sp, msg); } // Which arm's failure should we report? (the one furthest along) let mut best_failure: Option<(Token, &str)> = None; + + // We create a base parser that can be used for the "black box" parts. + // Every iteration needs a fresh copy of that base parser. However, the + // parser is not mutated on many of the iterations, particularly when + // dealing with macros like this: + // + // macro_rules! foo { + // ("a") => (A); + // ("b") => (B); + // ("c") => (C); + // // ... etc. (maybe hundreds more) + // } + // + // as seen in the `html5ever` benchmark. We use a `Cow` so that the base + // parser is only cloned when necessary (upon mutation). Furthermore, we + // reinitialize the `Cow` with the base parser at the start of every + // iteration, so that any mutated parsers are not reused. This is all quite + // hacky, but speeds up the `html5ever` benchmark significantly. (Issue + // 68836 suggests a more comprehensive but more complex change to deal with + // this situation.) + let base_parser = base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + for (i, lhs) in lhses.iter().enumerate() { + let mut parser = Cow::Borrowed(&base_parser); + // try each arm's matchers let lhs_tt = match *lhs { mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], @@ -202,7 +226,7 @@ fn generic_extension<'cx>( // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut()); - match parse_tt(cx, lhs_tt, arg.clone()) { + match parse_tt(&mut parser, lhs_tt) { Success(named_matches) => { // The matcher was `Success(..)`ful. // Merge the gated spans from parsing the matcher with the pre-existing ones. @@ -232,11 +256,11 @@ fn generic_extension<'cx>( if cx.trace_macros() { let msg = format!("to `{}`", pprust::tts_to_string(tts.clone())); - trace_macros_note(cx, sp, msg); + trace_macros_note(&mut cx.expansions, sp, msg); } let directory = Directory { - path: Cow::from(cx.current_expansion.module.directory.as_path()), + path: cx.current_expansion.module.directory.clone(), ownership: cx.current_expansion.directory_ownership, }; let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None); @@ -269,6 +293,7 @@ fn generic_extension<'cx>( // Restore to the state before snapshotting and maybe try again. mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut()); } + drop(base_parser); let (token, label) = best_failure.expect("ran no matchers"); let span = token.span.substitute_dummy(sp); @@ -286,7 +311,9 @@ fn generic_extension<'cx>( mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; - match parse_tt(cx, lhs_tt, arg.clone()) { + let base_parser = + base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + match parse_tt(&mut Cow::Borrowed(&base_parser), lhs_tt) { Success(_) => { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -368,7 +395,8 @@ pub fn compile_declarative_macro( ), ]; - let argument_map = match parse(sess, body, &argument_gram, None, true) { + let base_parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS); + let argument_map = match parse_tt(&mut Cow::Borrowed(&base_parser), &argument_gram) { Success(m) => m, Failure(token, msg) => { let s = parse_failure_msg(&token); @@ -1184,14 +1212,16 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -/// Use this token tree as a matcher to parse given tts. -fn parse_tt(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) -> NamedParseResult { - // `None` is because we're not interpolating +fn base_parser_from_cx<'cx>( + current_expansion: &'cx ExpansionData, + sess: &'cx ParseSess, + tts: TokenStream, +) -> Parser<'cx> { let directory = Directory { - path: Cow::from(cx.current_expansion.module.directory.as_path()), - ownership: cx.current_expansion.directory_ownership, + path: current_expansion.module.directory.clone(), + ownership: current_expansion.directory_ownership, }; - parse(cx.parse_sess(), tts, mtch, Some(directory), true) + Parser::new(sess, tts, Some(directory), true, true, rustc_parse::MACRO_ARGUMENTS) } /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index cd674e3c5ebef..4aad2c0f68a29 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -12,8 +12,7 @@ use syntax::ast; use syntax::token::{self, Nonterminal}; use syntax::tokenstream::{self, TokenStream, TokenTree}; -use std::borrow::Cow; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str; use log::info; @@ -29,8 +28,8 @@ pub mod validate_attr; pub mod config; #[derive(Clone)] -pub struct Directory<'a> { - pub path: Cow<'a, Path>, +pub struct Directory { + pub path: PathBuf, pub ownership: DirectoryOwnership, } @@ -274,7 +273,7 @@ pub fn stream_to_parser<'a>( pub fn stream_to_parser_with_base_dir<'a>( sess: &'a ParseSess, stream: TokenStream, - base_dir: Directory<'a>, + base_dir: Directory, ) -> Parser<'a> { Parser::new(sess, stream, Some(base_dir), true, false, None) } diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 37b03cf32f49c..e1461dbb8e763 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -29,7 +29,6 @@ use syntax::token::{self, DelimToken, Token, TokenKind}; use syntax::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use syntax::util::comments::{doc_comment_style, strip_doc_comment_decoration}; -use std::borrow::Cow; use std::path::PathBuf; use std::{cmp, mem, slice}; @@ -108,7 +107,7 @@ pub struct Parser<'a> { pub prev_span: Span, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. - pub(super) directory: Directory<'a>, + pub(super) directory: Directory, /// `true` to parse sub-modules in other files. // Public for rustfmt usage. pub recurse_into_file_modules: bool, @@ -370,7 +369,7 @@ impl<'a> Parser<'a> { pub fn new( sess: &'a ParseSess, tokens: TokenStream, - directory: Option>, + directory: Option, recurse_into_file_modules: bool, desugar_doc_comments: bool, subparser_name: Option<&'static str>, @@ -385,7 +384,7 @@ impl<'a> Parser<'a> { restrictions: Restrictions::empty(), recurse_into_file_modules, directory: Directory { - path: Cow::from(PathBuf::new()), + path: PathBuf::new(), ownership: DirectoryOwnership::Owned { relative: None }, }, root_module_name: None, @@ -413,7 +412,7 @@ impl<'a> Parser<'a> { &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { if let Some(directory_path) = path.parent() { - parser.directory.path = Cow::from(directory_path.to_path_buf()); + parser.directory.path = directory_path.to_path_buf(); } } } diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 6ce94d3c6793c..0c8fad03d8690 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -285,7 +285,7 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - self.directory.path.to_mut().push(&*path.as_str()); + self.directory.path.push(&*path.as_str()); self.directory.ownership = DirectoryOwnership::Owned { relative: None }; } else { // We have to push on the current module name in the case of relative @@ -297,10 +297,10 @@ impl<'a> Parser<'a> { if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { if let Some(ident) = relative.take() { // remove the relative offset - self.directory.path.to_mut().push(&*ident.as_str()); + self.directory.path.push(&*ident.as_str()); } } - self.directory.path.to_mut().push(&*id.as_str()); + self.directory.path.push(&*id.as_str()); } } } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 3c2e02fc79b3a..4a98095ec89c6 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -24,6 +24,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr); self.suggest_compatible_variants(err, expr, expected, expr_ty); self.suggest_ref_or_into(err, expr, expected, expr_ty); + if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { + return; + } self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); self.suggest_missing_await(err, expr, expected, expr_ty); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0bdf7ba1a569e..fd0c994a6eadf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5038,14 +5038,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); err.note( - "for more on the distinction between the stack and the \ - heap, read https://doc.rust-lang.org/book/ch15-01-box.html, \ - https://doc.rust-lang.org/rust-by-example/std/box.html, and \ - https://doc.rust-lang.org/std/boxed/index.html", + "for more on the distinction between the stack and the heap, read \ + https://doc.rust-lang.org/book/ch15-01-box.html, \ + https://doc.rust-lang.org/rust-by-example/std/box.html, and \ + https://doc.rust-lang.org/std/boxed/index.html", ); } } + /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. + fn suggest_calling_boxed_future_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + // Handle #68197. + + if self.tcx.hir().is_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return false; + } + let pin_did = self.tcx.lang_items().pin_type(); + match expected.kind { + ty::Adt(def, _) if Some(def.did) != pin_did => return false, + // This guards the `unwrap` and `mk_box` below. + _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, + _ => {} + } + let boxed_found = self.tcx.mk_box(found); + let new_found = self.tcx.mk_lang_item(boxed_found, lang_items::PinTypeLangItem).unwrap(); + if let (true, Ok(snippet)) = ( + self.can_coerce(new_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + match found.kind { + ty::Adt(def, _) if def.is_box() => { + err.help("use `Box::pin`"); + } + _ => { + err.span_suggestion( + expr.span, + "you need to pin and box this expression", + format!("Box::pin({})", snippet), + Applicability::MachineApplicable, + ); + } + } + true + } else { + false + } + } + /// A common error is to forget to add a semicolon at the end of a block, e.g., /// /// ``` diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ea0e4719a24fd..f3a1f412d0d59 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -278,6 +278,17 @@ impl ItemCtxt<'tcx> { pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> { AstConv::ast_ty_to_ty(self, ast_ty) } + + pub fn hir_id(&self) -> hir::HirId { + self.tcx + .hir() + .as_local_hir_id(self.item_def_id) + .expect("Non-local call to local provider is_const_fn") + } + + pub fn node(&self) -> hir::Node<'tcx> { + self.tcx.hir().get(self.hir_id()) + } } impl AstConv<'tcx> for ItemCtxt<'tcx> { @@ -290,15 +301,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } fn default_constness_for_trait_bounds(&self) -> ast::Constness { - // FIXME: refactor this into a method - let hir_id = self - .tcx - .hir() - .as_local_hir_id(self.item_def_id) - .expect("Non-local call to local provider is_const_fn"); - - let node = self.tcx.hir().get(hir_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { + if let Some(fn_like) = FnLikeNode::from_node(self.node()) { fn_like.constness() } else { ast::Constness::NotConst @@ -352,14 +355,80 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().mk_projection(item_def_id, item_substs) } else { // There are no late-bound regions; we can just ignore the binder. - struct_span_err!( + let mut err = struct_span_err!( self.tcx().sess, span, E0212, "cannot extract an associated type from a higher-ranked trait bound \ in this context" - ) - .emit(); + ); + + match self.node() { + hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => { + let item = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id())); + match &item.kind { + hir::ItemKind::Enum(_, generics) + | hir::ItemKind::Struct(_, generics) + | hir::ItemKind::Union(_, generics) => { + // FIXME: look for an appropriate lt name if `'a` is already used + let (lt_sp, sugg) = match &generics.params[..] { + [] => (generics.span, "<'a>".to_string()), + [bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()), + }; + let suggestions = vec![ + (lt_sp, sugg), + ( + span, + format!( + "{}::{}", + // Replace the existing lifetimes with a new named lifetime. + self.tcx + .replace_late_bound_regions(&poly_trait_ref, |_| { + self.tcx.mk_region(ty::ReEarlyBound( + ty::EarlyBoundRegion { + def_id: item_def_id, + index: 0, + name: Symbol::intern("'a"), + }, + )) + }) + .0, + item_segment.ident + ), + ), + ]; + err.multipart_suggestion( + "use a fully qualified path with explicit lifetimes", + suggestions, + Applicability::MaybeIncorrect, + ); + } + _ => {} + } + } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(..), .. }) => {} + hir::Node::Item(_) + | hir::Node::ForeignItem(_) + | hir::Node::TraitItem(_) + | hir::Node::ImplItem(_) => { + err.span_suggestion( + span, + "use a fully qualified path with inferred lifetimes", + format!( + "{}::{}", + // Erase named lt, we want `::C`, not `::C`. + self.tcx.anonymize_late_bound_regions(&poly_trait_ref).skip_binder(), + item_segment.ident + ), + Applicability::MaybeIncorrect, + ); + } + _ => {} + } + err.emit(); self.tcx().types.err } } @@ -1054,7 +1123,27 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { Some(tcx.closure_base_def_id(def_id)) } Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => impl_trait_fn, + ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { + impl_trait_fn.or_else(|| { + let parent_id = tcx.hir().get_parent_item(hir_id); + if parent_id != hir_id && parent_id != CRATE_HIR_ID { + debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); + // If this 'impl Trait' is nested inside another 'impl Trait' + // (e.g. `impl Foo>`), we need to use the 'parent' + // 'impl Trait' for its generic parameters, since we can reference them + // from the 'child' 'impl Trait' + if let Node::Item(hir::Item { kind: ItemKind::OpaqueTy(..), .. }) = + tcx.hir().get(parent_id) + { + Some(tcx.hir().local_def_id(parent_id)) + } else { + None + } + } else { + None + } + }) + } _ => None, }, _ => None, diff --git a/src/librustdoc/html/static/brush.svg b/src/librustdoc/html/static/brush.svg index 072264a640830..ea266e856a9d8 100644 --- a/src/librustdoc/html/static/brush.svg +++ b/src/librustdoc/html/static/brush.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/librustdoc/html/static/down-arrow.svg b/src/librustdoc/html/static/down-arrow.svg index c0f59f0c36fce..35437e77a710c 100644 --- a/src/librustdoc/html/static/down-arrow.svg +++ b/src/librustdoc/html/static/down-arrow.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/librustdoc/html/static/wheel.svg b/src/librustdoc/html/static/wheel.svg index 44381a401a82f..01da3b24c7c4f 100644 --- a/src/librustdoc/html/static/wheel.svg +++ b/src/librustdoc/html/static/wheel.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index b8242f7154ee4..1fe6a309e9650 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -1,46 +1,14 @@ -#[inline] -pub fn write_to_vec(vec: &mut Vec, byte: u8) { - vec.push(byte); -} - -#[cfg(target_pointer_width = "32")] -const USIZE_LEB128_SIZE: usize = 5; -#[cfg(target_pointer_width = "64")] -const USIZE_LEB128_SIZE: usize = 10; - -macro_rules! leb128_size { - (u16) => { - 3 - }; - (u32) => { - 5 - }; - (u64) => { - 10 - }; - (u128) => { - 19 - }; - (usize) => { - USIZE_LEB128_SIZE - }; -} - macro_rules! impl_write_unsigned_leb128 { ($fn_name:ident, $int_ty:ident) => { #[inline] pub fn $fn_name(out: &mut Vec, mut value: $int_ty) { - for _ in 0..leb128_size!($int_ty) { - let mut byte = (value & 0x7F) as u8; - value >>= 7; - if value != 0 { - byte |= 0x80; - } - - write_to_vec(out, byte); - - if value == 0 { + loop { + if value < 0x80 { + out.push(value as u8); break; + } else { + out.push(((value & 0x7f) | 0x80) as u8); + value >>= 7; } } } @@ -57,24 +25,20 @@ macro_rules! impl_read_unsigned_leb128 { ($fn_name:ident, $int_ty:ident) => { #[inline] pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) { - let mut result: $int_ty = 0; + let mut result = 0; let mut shift = 0; let mut position = 0; - - for _ in 0..leb128_size!($int_ty) { - let byte = unsafe { *slice.get_unchecked(position) }; + loop { + let byte = slice[position]; position += 1; - result |= ((byte & 0x7F) as $int_ty) << shift; if (byte & 0x80) == 0 { - break; + result |= (byte as $int_ty) << shift; + return (result, position); + } else { + result |= ((byte & 0x7F) as $int_ty) << shift; } shift += 7; } - - // Do a single bounds check at the end instead of for every byte. - assert!(position <= slice.len()); - - (result, position) } }; } @@ -116,7 +80,7 @@ where #[inline] pub fn write_signed_leb128(out: &mut Vec, value: i128) { - write_signed_leb128_to(value, |v| write_to_vec(out, v)) + write_signed_leb128_to(value, |v| out.push(v)) } #[inline] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fdc587ba5dacf..d0e1a01b00654 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -203,7 +203,7 @@ pub struct HashMap { base: base::HashMap, } -impl HashMap { +impl HashMap { /// Creates an empty `HashMap`. /// /// The hash map is initially created with a capacity of 0, so it will not allocate until it @@ -240,6 +240,59 @@ impl HashMap { } impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_hasher(hash_builder: S) -> HashMap { + HashMap { base: base::HashMap::with_hasher(hash_builder) } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { + HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) } + } + /// Returns the number of elements the map can hold without reallocating. /// /// This number is a lower bound; the `HashMap` might be able to hold @@ -457,65 +510,6 @@ impl HashMap { pub fn clear(&mut self) { self.base.clear(); } -} - -impl HashMap -where - K: Eq + Hash, - S: BuildHasher, -{ - /// Creates an empty `HashMap` which will use the given hash builder to hash - /// keys. - /// - /// The created map has the default initial capacity. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut map = HashMap::with_hasher(s); - /// map.insert(1, 2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_hasher(hash_builder: S) -> HashMap { - HashMap { base: base::HashMap::with_hasher(hash_builder) } - } - - /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` - /// to hash the keys. - /// - /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, s); - /// map.insert(1, 2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { - HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) } - } /// Returns a reference to the map's [`BuildHasher`]. /// @@ -536,7 +530,13 @@ where pub fn hasher(&self) -> &S { self.base.hasher() } +} +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, +{ /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashMap`. The collection may reserve more space to avoid /// frequent reallocations. @@ -984,9 +984,8 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Debug for HashMap where - K: Eq + Hash + Debug, + K: Debug, V: Debug, - S: BuildHasher, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -996,8 +995,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashMap where - K: Eq + Hash, - S: BuildHasher + Default, + S: Default, { /// Creates an empty `HashMap`, with the `Default` value for the hasher. #[inline] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b48700fb94420..1ad99f03703dd 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -110,7 +110,7 @@ pub struct HashSet { map: HashMap, } -impl HashSet { +impl HashSet { /// Creates an empty `HashSet`. /// /// The hash set is initially created with a capacity of 0, so it will not allocate until it @@ -261,13 +261,7 @@ impl HashSet { pub fn clear(&mut self) { self.map.clear() } -} -impl HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// @@ -340,7 +334,13 @@ where pub fn hasher(&self) -> &S { self.map.hasher() } +} +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, +{ /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to avoid /// frequent reallocations. @@ -928,8 +928,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for HashSet where - T: Eq + Hash + fmt::Debug, - S: BuildHasher, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() @@ -977,8 +976,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashSet where - T: Eq + Hash, - S: BuildHasher + Default, + S: Default, { /// Creates an empty `HashSet` with the `Default` value for the hasher. #[inline] diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs index b47a48e752cb7..5a53695a8466b 100644 --- a/src/libstd/sys/sgx/args.rs +++ b/src/libstd/sys/sgx/args.rs @@ -22,12 +22,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } } -pub unsafe fn cleanup() { - let args = ARGS.swap(0, Ordering::Relaxed); - if args != 0 { - drop(Box::::from_raw(args as _)) - } -} +pub unsafe fn cleanup() {} pub fn args() -> Args { let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() }; diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed new file mode 100644 index 0000000000000..760d2b433c87a --- /dev/null +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed @@ -0,0 +1,37 @@ +#![allow(dead_code, unused_variables)] +// run-rustfix +// Check projection of an associated type out of a higher-ranked trait-bound +// in the context of a function signature. + +pub trait Foo { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo2 Foo<&'x isize>>( + x: >::A) + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context +{ + // This case is illegal because we have to instantiate `'x`, and + // we don't know what region to instantiate it with. + // + // This could perhaps be made equivalent to the examples below, + // specifically for fn signatures. +} + +fn foo3 Foo<&'x isize>>( + x: >::A) +{ + // OK, in this case we spelled out the precise regions involved, though we left one of + // them anonymous. +} + +fn foo4<'a, I : for<'x> Foo<&'x isize>>( + x: >::A) +{ + // OK, in this case we spelled out the precise regions involved. +} + + +pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs index bf13c410cc60b..6eb584ea645ac 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs @@ -1,3 +1,5 @@ +#![allow(dead_code, unused_variables)] +// run-rustfix // Check projection of an associated type out of a higher-ranked trait-bound // in the context of a function signature. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr index 09f4f99703f9c..f2137f68665db 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr @@ -1,8 +1,8 @@ error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context - --> $DIR/associated-types-project-from-hrtb-in-fn.rs:11:8 + --> $DIR/associated-types-project-from-hrtb-in-fn.rs:13:8 | LL | x: I::A) - | ^^^^ + | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs index 20f11ecf63823..8a5777d4d7cb5 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs @@ -7,18 +7,25 @@ pub trait Foo { fn get(&self, t: T) -> Self::A; } -struct SomeStruct Foo<&'x isize>> { +struct SomeStruct Foo<&'x isize>> { field: I::A //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } +enum SomeEnum Foo<&'x isize>> { + TupleVariant(I::A), + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + StructVariant { field: I::A }, + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context +} + // FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. // struct AnotherStruct Foo<&'x isize>> { // field: Foo<&'y isize>>::A // } -struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> { +struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> { field: >::A } diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index 189b19461f479..c71bc70ea6c4e 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -3,6 +3,38 @@ error[E0212]: cannot extract an associated type from a higher-ranked trait bound | LL | field: I::A | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | struct SomeStruct<'a, I: for<'x> Foo<&'x isize>> { +LL | field: >::A + | + +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:16:18 + | +LL | TupleVariant(I::A), + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | TupleVariant(>::A), + | + +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:18:28 + | +LL | StructVariant { field: I::A }, + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | TupleVariant(I::A), +LL | +LL | StructVariant { field: >::A }, + | -error: aborting due to previous error +error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed new file mode 100644 index 0000000000000..acf32bccbecfd --- /dev/null +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed @@ -0,0 +1,38 @@ +#![allow(dead_code)] +// run-rustfix +// Check projection of an associated type out of a higher-ranked trait-bound +// in the context of a method definition in a trait. + +pub trait Foo { + type A; + + fn get(&self, t: T) -> Self::A; +} + +trait SomeTrait Foo<&'x isize>> { + fn some_method(&self, arg: >::A); + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context +} + +trait AnotherTrait Foo<&'x isize>> { + fn some_method(&self, arg: >::A); +} + +trait YetAnotherTrait Foo<&'x isize>> { + fn some_method<'a>(&self, arg: >::A); +} + +trait Banana<'a> { + type Assoc: Default; +} + +struct Peach(std::marker::PhantomData); + +impl Banana<'a>> Peach { + fn mango(&self) -> >::Assoc { + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + Default::default() + } +} + +pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs index cb52c2b4f15d6..a249f89685e39 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] +// run-rustfix // Check projection of an associated type out of a higher-ranked trait-bound // in the context of a method definition in a trait. @@ -20,4 +22,17 @@ trait YetAnotherTrait Foo<&'x isize>> { fn some_method<'a>(&self, arg: >::A); } +trait Banana<'a> { + type Assoc: Default; +} + +struct Peach(std::marker::PhantomData); + +impl Banana<'a>> Peach { + fn mango(&self) -> X::Assoc { + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + Default::default() + } +} + pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr index e1c169028c5c4..a37fec244933c 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr @@ -1,8 +1,14 @@ error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context - --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:11:32 + --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:13:32 | LL | fn some_method(&self, arg: I::A); - | ^^^^ + | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A` -error: aborting due to previous error +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:32:24 + | +LL | fn mango(&self) -> X::Assoc { + | ^^^^^^^^ help: use a fully qualified path with inferred lifetimes: `>::Assoc` + +error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs index 7fa059583f539..8397d204f35cf 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs @@ -6,7 +6,6 @@ pub fn no_debug() { pub fn no_hash() { use std::collections::HashSet; let mut set = HashSet::new(); - //~^ ERROR arrays only have std trait implementations for lengths 0..=32 set.insert([0_usize; 33]); //~^ ERROR arrays only have std trait implementations for lengths 0..=32 } diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr index cba71db86a964..781a179624e77 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr @@ -9,24 +9,15 @@ LL | println!("{:?}", [0_usize; 33]); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/core-traits-no-impls-length-33.rs:10:16 + --> $DIR/core-traits-no-impls-length-33.rs:9:16 | LL | set.insert([0_usize; 33]); | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` | = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]` -error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/core-traits-no-impls-length-33.rs:8:19 - | -LL | let mut set = HashSet::new(); - | ^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` - | - = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]` - = note: required by `std::collections::HashSet::::new` - error[E0369]: binary operation `==` cannot be applied to type `[usize; 33]` - --> $DIR/core-traits-no-impls-length-33.rs:15:19 + --> $DIR/core-traits-no-impls-length-33.rs:14:19 | LL | [0_usize; 33] == [1_usize; 33] | ------------- ^^ ------------- [usize; 33] @@ -36,7 +27,7 @@ LL | [0_usize; 33] == [1_usize; 33] = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]` error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]` - --> $DIR/core-traits-no-impls-length-33.rs:20:19 + --> $DIR/core-traits-no-impls-length-33.rs:19:19 | LL | [0_usize; 33] < [1_usize; 33] | ------------- ^ ------------- [usize; 33] @@ -46,7 +37,7 @@ LL | [0_usize; 33] < [1_usize; 33] = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]` error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied - --> $DIR/core-traits-no-impls-length-33.rs:25:14 + --> $DIR/core-traits-no-impls-length-33.rs:24:14 | LL | for _ in &[0_usize; 33] { | ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]` @@ -58,7 +49,7 @@ LL | for _ in &[0_usize; 33] { <&'a mut [T] as std::iter::IntoIterator> = note: required by `std::iter::IntoIterator::into_iter` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0277, E0369. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/static-not-unpin.rs b/src/test/ui/generator/static-not-unpin.rs index b271e982fb420..cfcb94737be6f 100644 --- a/src/test/ui/generator/static-not-unpin.rs +++ b/src/test/ui/generator/static-not-unpin.rs @@ -11,5 +11,5 @@ fn main() { let mut generator = static || { yield; }; - assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied + assert_unpin(generator); //~ ERROR E0277 } diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index f2b1078e2b532..6512d67319b0b 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned --> $DIR/static-not-unpin.rs:14:18 | LL | fn assert_unpin(_: T) { diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs new file mode 100644 index 0000000000000..0a1686eac9d34 --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -0,0 +1,29 @@ +// edition:2018 +#![allow(dead_code)] +use std::future::Future; +use std::pin::Pin; + +type BoxFuture<'a, T> = Pin + Send + 'a>>; +// ^^^^^^^^^ This would come from the `futures` crate in real code. + +fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + // We could instead use an `async` block, but this way we have no std spans. + x //~ ERROR mismatched types +} + +// FIXME: uncomment these once this commit is in Beta and we can rely on `rustc_on_unimplemented` +// having filtering for `Self` being a trait. +// +// fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { +// Box::new(x) +// } +// +// fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { +// Pin::new(x) +// } +// +// fn qux + Send + 'static>(x: F) -> BoxFuture<'static, i32> { +// Pin::new(Box::new(x)) +// } + +fn main() {} diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr new file mode 100644 index 0000000000000..48d941283b62d --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5 + | +LL | fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + | - this type parameter ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type +LL | // We could instead use an `async` block, but this way we have no std spans. +LL | x + | ^ + | | + | expected struct `std::pin::Pin`, found type parameter `F` + | help: you need to pin and box this expression: `Box::pin(x)` + | + = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` + found type parameter `F` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs b/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs new file mode 100644 index 0000000000000..2f844b4a05f5f --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs @@ -0,0 +1,32 @@ +// check-pass +// Regression test for issue #67844 +// Ensures that we properly handle nested TAIT occurences +// with generic parameters + +#![feature(type_alias_impl_trait)] + +trait WithAssoc { type AssocType; } + +trait WithParam {} + +type Return = impl WithAssoc>; + +struct MyParam; +impl WithParam for MyParam {} + +struct MyStruct; + +impl WithAssoc for MyStruct { + type AssocType = MyParam; +} + + +fn my_fun() -> Return { + MyStruct +} + +fn my_other_fn() -> impl WithAssoc> { + MyStruct +} + +fn main() {}