From b2c0fd087682c7cd61dbf44f02cefd28b0d230ed Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Sun, 21 Apr 2019 15:19:53 -0700 Subject: [PATCH 01/22] Remove redundant code in copy_clone_conditions This was left over from when closure copy and clone were gated behind feature flags. --- src/librustc/traits/select.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e7cc9618080c2..cf69885c3e07c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2505,16 +2505,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::Closure(def_id, substs) => { - let trait_id = obligation.predicate.def_id(); - let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait(); - let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait(); - if is_copy_trait || is_clone_trait { - Where(ty::Binder::bind( - substs.upvar_tys(def_id, self.tcx()).collect(), - )) - } else { - None - } + // (*) binder moved here + Where(ty::Binder::bind( + substs.upvar_tys(def_id, self.tcx()).collect(), + )) } ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { From d676386b1e4ffdbd76e846ccf24c80fb4c7926ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Apr 2019 16:44:20 +0200 Subject: [PATCH 02/22] Fix index-page generation --- Cargo.lock | 6 +++--- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/html/render.rs | 7 ++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b62c7ff90970e..91de0c4fab988 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1513,7 +1513,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.29" +version = "0.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3018,7 +3018,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4148,7 +4148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4950cb2617b1933e2da0446e864dfe0d6a22c22ff72297996c46e6a63b210b" +"checksum minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "4c909e78edf61f3aa0dd2086da168cdf304329044bbf248768ca3d20253ec8c0" "checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" "checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" "checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 4941867d8dfcd..6cedab412df92 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.4.1", default-features = false } -minifier = "0.0.29" +minifier = "0.0.30" tempfile = "3" parking_lot = "0.7" diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d91b78c8416b8..fb33ee3f3045a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1340,10 +1340,15 @@ fn write_minify_replacer( .into(); tokens.apply(|f| { // We add a backline after the newly created variables. - minifier::js::aggregate_strings_into_array_with_separation( + minifier::js::aggregate_strings_into_array_with_separation_filter( f, "R", Token::Char(ReservedChar::Backline), + |tokens, pos| { + pos < 2 || + !tokens[pos - 1].is_char(ReservedChar::OpenBracket) || + tokens[pos - 2].get_other() != Some("searchIndex") + } ) }) .to_string() From 64f7cede8b8431d6c2def2720a2c3077db948b73 Mon Sep 17 00:00:00 2001 From: sd234678 Date: Wed, 24 Apr 2019 13:47:26 +0100 Subject: [PATCH 03/22] Derive Default instead of new in applicable lint --- src/librustc_lint/builtin.rs | 7 +------ src/librustc_lint/lib.rs | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 57bc44ee30cd9..c01c334030343 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -542,18 +542,13 @@ declare_lint! { "detects missing implementations of fmt::Debug" } +#[derive(Default)] pub struct MissingDebugImplementations { impling_types: Option, } impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); -impl MissingDebugImplementations { - pub fn new() -> MissingDebugImplementations { - MissingDebugImplementations { impling_types: None } - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { if !cx.access_levels.is_reachable(item.hir_id) { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 68ea219561962..e7e6ffac517a0 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -132,7 +132,7 @@ macro_rules! late_lint_passes { // Depends on access levels // FIXME: Turn the computation of types which implement Debug into a query // and change this to a module lint pass - MissingDebugImplementations: MissingDebugImplementations::new(), + MissingDebugImplementations: MissingDebugImplementations::default(), ]); ) } From ef37f38726658dc51e3306171595d638eba4006d Mon Sep 17 00:00:00 2001 From: sd234678 Date: Wed, 24 Apr 2019 19:38:10 +0100 Subject: [PATCH 04/22] Derive Default for EllipsisInclusiveRangePatterns --- src/librustc_lint/builtin.rs | 9 +-------- src/librustc_lint/lib.rs | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c01c334030343..47c1c16f1f828 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1280,6 +1280,7 @@ declare_lint! { "`...` range patterns are deprecated" } +#[derive(Default)] pub struct EllipsisInclusiveRangePatterns { /// If `Some(_)`, suppress all subsequent pattern /// warnings for better diagnostics. @@ -1288,14 +1289,6 @@ pub struct EllipsisInclusiveRangePatterns { impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]); -impl EllipsisInclusiveRangePatterns { - pub fn new() -> Self { - Self { - node_id: None, - } - } -} - impl EarlyLintPass for EllipsisInclusiveRangePatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) { if self.node_id.is_some() { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e7e6ffac517a0..7d23da857bbbb 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -94,7 +94,7 @@ macro_rules! early_lint_passes { UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, AnonymousParameters: AnonymousParameters, - EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::new(), + EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, DeprecatedAttr: DeprecatedAttr::new(), ]); From a0e0849a3b1710139d84be846a444c12297cfd2b Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 21 Apr 2019 13:27:36 +0200 Subject: [PATCH 05/22] Add Pin::{into_inner,into_inner_unchecked} --- src/libcore/pin.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index dbf3dcf03a3c0..e74ed9b7889cb 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -349,6 +349,18 @@ where // around pinning. unsafe { Pin::new_unchecked(pointer) } } + + /// Unwraps this `Pin

` returning the underlying pointer. + /// + /// This requires that the data inside this `Pin` is [`Unpin`] so that we + /// can ignore the pinning invariants when unwrapping it. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html + #[unstable(feature = "pin_into_inner", issue = "60245")] + #[inline(always)] + pub fn into_inner(pin: Pin

) -> P { + pin.pointer + } } impl Pin

{ @@ -434,6 +446,28 @@ impl Pin

{ pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { unsafe { Pin::new_unchecked(&*self.pointer) } } + + /// Unwraps this `Pin

` returning the underlying pointer. + /// + /// # Safety + /// + /// This function is unsafe. You must guarantee that you will continue to + /// treat the pointer `P` as pinned after you call this function, so that + /// the invariants on the `Pin` type can be upheld. If the code using the + /// resulting `P` does not continue to maintain the pinning invariants that + /// is a violation of the API contract and may lead to undefined behavior in + /// later (safe) operations. + /// + /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used + /// instead. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html + /// [`Pin::into_inner`]: #method.into_inner + #[unstable(feature = "pin_into_inner", issue = "60245")] + #[inline(always)] + pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { + pin.pointer + } } impl Pin

{ From 8ed2292dbe75b9b65e9fe1a079428d1e1e3b610f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 13 Apr 2019 18:00:40 +0200 Subject: [PATCH 06/22] Set test flag when rustdoc is running with --test option --- src/librustdoc/config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 769ea3ff7bc74..72421c9decc6f 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -351,6 +351,9 @@ impl Options { .unwrap_or_else(|| PathBuf::from("doc")); let mut cfgs = matches.opt_strs("cfg"); cfgs.push("rustdoc".to_string()); + if should_test { + cfgs.push("test".to_string()); + } let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); From 459d677bfffa0adeef75218d1cfa5f686e413f4d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 24 Apr 2019 22:26:42 +0200 Subject: [PATCH 07/22] Add test for rustdoc cfg(test) feature --- src/test/rustdoc-ui/cfg-test.rs | 19 +++++++++++++++++++ src/test/rustdoc-ui/cfg-test.stdout | 6 ++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/rustdoc-ui/cfg-test.rs create mode 100644 src/test/rustdoc-ui/cfg-test.stdout diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs new file mode 100644 index 0000000000000..e26034371f444 --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.rs @@ -0,0 +1,19 @@ +// compile-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" + +/// this doctest will be ignored: +/// +/// ``` +/// assert!(false); +/// ``` +#[cfg(not(test))] +pub struct Foo; + +/// this doctest will be tested: +/// +/// ``` +/// assert!(true); +/// ``` +#[cfg(test)] +pub struct Foo; diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout new file mode 100644 index 0000000000000..30bb0038d1b8d --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/cfg-test.rs - Foo (line 15) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + From feb5a53266902d9c66bf9e5ef5e28fe1534a01a9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Apr 2019 21:31:11 +0200 Subject: [PATCH 08/22] Prevent failure in case no space left on device in rustdoc --- src/librustdoc/html/render.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d91b78c8416b8..8eb04e3722786 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1358,7 +1358,8 @@ fn write_minify_replacer( /// static HTML tree. Each component in the cleaned path will be passed as an /// argument to `f`. The very last component of the path (ie the file name) will /// be passed to `f` if `keep_filename` is true, and ignored otherwise. -fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) where +fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +where F: FnMut(&OsStr), { // make it relative, if possible @@ -1470,11 +1471,11 @@ impl<'a> SourceCollector<'a> { let mut href = String::new(); clean_srcpath(&self.scx.src_root, &p, false, |component| { cur.push(component); - fs::create_dir_all(&cur).unwrap(); root_path.push_str("../"); href.push_str(&component.to_string_lossy()); href.push('/'); }); + fs::create_dir_all(&cur)?; let mut fname = p.file_name() .expect("source has no filename") .to_os_string(); @@ -1483,7 +1484,7 @@ impl<'a> SourceCollector<'a> { href.push_str(&fname.to_string_lossy()); let mut w = BufWriter::new(File::create(&cur)?); - let title = format!("{} -- source", cur.file_name().unwrap() + let title = format!("{} -- source", cur.file_name().expect("failed to get file name") .to_string_lossy()); let desc = format!("Source to the Rust file `{}`.", filename); let page = layout::Page { From f199627e69baccdb44f41e945d189aa04d0df022 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 24 Apr 2019 23:45:18 +0200 Subject: [PATCH 09/22] Remove useless code and update index page test --- src/librustdoc/html/render.rs | 27 ++------------------------- src/test/rustdoc/index-page.rs | 3 +++ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index fb33ee3f3045a..703f7b18d160e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -951,40 +951,15 @@ themePicker.onblur = handleThemeButtonsBlur; key: &str, for_search_index: bool, ) -> io::Result<(Vec, Vec, Vec)> { - use minifier::js; - let mut ret = Vec::new(); let mut krates = Vec::new(); let mut variables = Vec::new(); - let mut krate = krate.to_owned(); - if path.exists() { for line in BufReader::new(File::open(path)?).lines() { let line = line?; if for_search_index && line.starts_with("var R") { variables.push(line.clone()); - // We need to check if the crate name has been put into a variable as well. - let tokens: js::Tokens<'_> = js::simple_minify(&line) - .into_iter() - .filter(js::clean_token) - .collect::>() - .into(); - let mut pos = 0; - while pos < tokens.len() { - if let Some((var_pos, Some(value_pos))) = - js::get_variable_name_and_value_positions(&tokens, pos) { - if let Some(s) = tokens.0[value_pos].get_string() { - if &s[1..s.len() - 1] == krate { - if let Some(var) = tokens[var_pos].get_other() { - krate = var.to_owned(); - break - } - } - } - } - pos += 1; - } continue; } if !line.starts_with(key) { @@ -1344,6 +1319,8 @@ fn write_minify_replacer( f, "R", Token::Char(ReservedChar::Backline), + // This closure prevents crates' name to be aggregated. It allows to not + // have to look for crate's name into the strings array. |tokens, pos| { pos < 2 || !tokens[pos - 1].is_char(ReservedChar::OpenBracket) || diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index 6998e73529727..f0476f083b8a1 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -1,3 +1,5 @@ +// aux-build:all-item-types.rs +// build-aux-docs // compile-flags: -Z unstable-options --enable-index-page #![crate_name = "foo"] @@ -5,4 +7,5 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' // @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; From c75e0890beade386ff15acdcc1028497094cd867 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 22 Apr 2019 14:35:37 -0700 Subject: [PATCH 10/22] chalkify: Add Copy/Clone builtins --- .../chalk_context/program_clauses/builtin.rs | 149 +++++++++++++++--- .../chalk_context/program_clauses/mod.rs | 21 ++- .../run-pass/chalkify/builtin-copy-clone.rs | 43 +++++ 3 files changed, 192 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/chalkify/builtin-copy-clone.rs diff --git a/src/librustc_traits/chalk_context/program_clauses/builtin.rs b/src/librustc_traits/chalk_context/program_clauses/builtin.rs index ae9f1a27b9422..0c6e65d405a16 100644 --- a/src/librustc_traits/chalk_context/program_clauses/builtin.rs +++ b/src/librustc_traits/chalk_context/program_clauses/builtin.rs @@ -6,10 +6,42 @@ use rustc::traits::{ }; use rustc::ty; use rustc::ty::subst::{InternalSubsts, Subst}; +use rustc::hir; use rustc::hir::def_id::DefId; use crate::lowering::Lower; use crate::generic_types; +/// Returns a predicate of the form +/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...` +/// where `Trait` is specified by `trait_def_id`. +fn builtin_impl_clause( + tcx: ty::TyCtxt<'_, '_, 'tcx>, + ty: ty::Ty<'tcx>, + nested: &[ty::Ty<'tcx>], + trait_def_id: DefId +) -> ProgramClause<'tcx> { + ProgramClause { + goal: ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs_trait(ty, &[]), + }, + }.lower(), + hypotheses: tcx.mk_goals( + nested.iter() + .cloned() + .map(|nested_ty| ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs_trait(nested_ty, &[]), + }) + .map(|trait_ref| ty::TraitPredicate { trait_ref }) + .map(|pred| GoalKind::DomainGoal(pred.lower())) + .map(|goal_kind| tcx.mk_goal(goal_kind)) + ), + category: ProgramClauseCategory::Other, + } +} + crate fn assemble_builtin_unsize_impls<'tcx>( tcx: ty::TyCtxt<'_, '_, 'tcx>, unsize_def_id: DefId, @@ -93,26 +125,7 @@ crate fn assemble_builtin_sized_impls<'tcx>( clauses: &mut Vec> ) { let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { - let clause = ProgramClause { - goal: ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: sized_def_id, - substs: tcx.mk_substs_trait(ty, &[]), - }, - }.lower(), - hypotheses: tcx.mk_goals( - nested.iter() - .cloned() - .map(|nested_ty| ty::TraitRef { - def_id: sized_def_id, - substs: tcx.mk_substs_trait(nested_ty, &[]), - }) - .map(|trait_ref| ty::TraitPredicate { trait_ref }) - .map(|pred| GoalKind::DomainGoal(pred.lower())) - .map(|goal_kind| tcx.mk_goal(goal_kind)) - ), - category: ProgramClauseCategory::Other, - }; + let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id); // Bind innermost bound vars that may exist in `ty` and `nested`. clauses.push(Clause::ForAll(ty::Binder::bind(clause))); }; @@ -206,3 +219,99 @@ crate fn assemble_builtin_sized_impls<'tcx>( ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty), } } + +crate fn assemble_builtin_copy_clone_impls<'tcx>( + tcx: ty::TyCtxt<'_, '_, 'tcx>, + trait_def_id: DefId, + ty: ty::Ty<'tcx>, + clauses: &mut Vec> +) { + let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { + let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id); + // Bind innermost bound vars that may exist in `ty` and `nested`. + clauses.push(Clause::ForAll(ty::Binder::bind(clause))); + }; + + match &ty.sty { + // Implementations provided in libcore. + ty::Bool | + ty::Char | + ty::Int(..) | + ty::Uint(..) | + ty::Float(..) | + ty::RawPtr(..) | + ty::Never | + ty::Ref(_, _, hir::MutImmutable) => (), + + // Non parametric primitive type. + ty::Error => push_builtin_impl(ty, &[]), + + // These implement `Copy`/`Clone` if their element types do. + &ty::Array(_, length) => { + let element_ty = generic_types::bound(tcx, 0); + push_builtin_impl(tcx.mk_ty(ty::Array(element_ty, length)), &[element_ty]); + } + &ty::Tuple(type_list) => { + let type_list = generic_types::type_list(tcx, type_list.len()); + push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list); + } + &ty::Closure(def_id, ..) => { + let closure_ty = generic_types::closure(tcx, def_id); + let upvar_tys: Vec<_> = match &closure_ty.sty { + ty::Closure(_, substs) => substs.upvar_tys(def_id, tcx).collect(), + _ => bug!(), + }; + push_builtin_impl(closure_ty, &upvar_tys); + } + + // These ones are always `Clone`. + ty::FnPtr(fn_ptr) => { + let fn_ptr = fn_ptr.skip_binder(); + let fn_ptr = generic_types::fn_ptr( + tcx, + fn_ptr.inputs_and_output.len(), + fn_ptr.c_variadic, + fn_ptr.unsafety, + fn_ptr.abi + ); + push_builtin_impl(fn_ptr, &[]); + } + &ty::FnDef(def_id, ..) => { + push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); + } + + // These depend on whatever user-defined impls might exist. + ty::Adt(_, _) => (), + + // int vars and float vars are always `Copy`. + // Other vars will trigger an ambiguity. + ty::Infer(..) => { + push_builtin_impl(tcx.types.i32, &[]); + push_builtin_impl(tcx.types.u32, &[]); + push_builtin_impl(tcx.types.f32, &[]); + push_builtin_impl(tcx.types.f64, &[]); + } + + ty::Projection(_projection_ty) => { + // FIXME: add builtin impls from the associated type values found in + // trait impls of `projection_ty.trait_ref(tcx)`. + } + + // The `Copy`/`Clone` bound can only come from the environment. + ty::Param(..) | + ty::Placeholder(..) | + ty::UnnormalizedProjection(..) | + ty::Opaque(..) => (), + + // Definitely not `Copy`/`Clone`. + ty::Dynamic(..) | + ty::Foreign(..) | + ty::Generator(..) | + ty::Str | + ty::Slice(..) | + ty::Ref(_, _, hir::MutMutable) => (), + + ty::Bound(..) | + ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty), + } +} diff --git a/src/librustc_traits/chalk_context/program_clauses/mod.rs b/src/librustc_traits/chalk_context/program_clauses/mod.rs index 80fbd97c5876b..7feb63bb10069 100644 --- a/src/librustc_traits/chalk_context/program_clauses/mod.rs +++ b/src/librustc_traits/chalk_context/program_clauses/mod.rs @@ -96,8 +96,27 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { ); } + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() { + assemble_builtin_copy_clone_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() { + // For all builtin impls, the conditions for `Copy` and + // `Clone` are the same. + assemble_builtin_copy_clone_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + // FIXME: we need to add special rules for other builtin impls: - // * `Copy` / `Clone` // * `Generator` // * `FnOnce` / `FnMut` / `Fn` // * trait objects diff --git a/src/test/run-pass/chalkify/builtin-copy-clone.rs b/src/test/run-pass/chalkify/builtin-copy-clone.rs new file mode 100644 index 0000000000000..4f69714bc747d --- /dev/null +++ b/src/test/run-pass/chalkify/builtin-copy-clone.rs @@ -0,0 +1,43 @@ +// compile-flags: -Z chalk + +// Test that `Clone` is correctly implemented for builtin types. + +#[derive(Copy, Clone)] +struct S(i32); + +fn test_clone(arg: T) { + let _ = arg.clone(); +} + +fn test_copy(arg: T) { + let _ = arg; + let _ = arg; +} + +fn test_copy_clone(arg: T) { + test_copy(arg); + test_clone(arg); +} + +fn foo() { } + +fn main() { + test_copy_clone(foo); + let f: fn() = foo; + test_copy_clone(f); + // FIXME: add closures when they're considered WF + test_copy_clone([1; 56]); + test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); + test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1)); + test_copy_clone(()); + test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ())); + + let a = ( + (S(1), S(0)), + ( + (S(0), S(0), S(1)), + S(0) + ) + ); + test_copy_clone(a); +} From 56ab3e70e7eeeaa9801c1e32c2a459df8dfc4ab8 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 24 Apr 2019 15:57:36 -0700 Subject: [PATCH 11/22] Add builtin impls for int and float inference vars in chalk --- .../chalk_context/program_clauses/builtin.rs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/librustc_traits/chalk_context/program_clauses/builtin.rs b/src/librustc_traits/chalk_context/program_clauses/builtin.rs index 0c6e65d405a16..27af8511915d1 100644 --- a/src/librustc_traits/chalk_context/program_clauses/builtin.rs +++ b/src/librustc_traits/chalk_context/program_clauses/builtin.rs @@ -137,6 +137,8 @@ crate fn assemble_builtin_sized_impls<'tcx>( ty::Int(..) | ty::Uint(..) | ty::Float(..) | + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) | ty::Error | ty::Never => push_builtin_impl(ty, &[]), @@ -188,14 +190,11 @@ crate fn assemble_builtin_sized_impls<'tcx>( push_builtin_impl(adt, &sized_constraint); } - // Artificially trigger an ambiguity. - ty::Infer(..) => { - // Everybody can find at least two types to unify against: - // general ty vars, int vars and float vars. + // Artificially trigger an ambiguity by adding two possible types to + // unify against. + ty::Infer(ty::TyVar(_)) => { push_builtin_impl(tcx.types.i32, &[]); - push_builtin_impl(tcx.types.u32, &[]); push_builtin_impl(tcx.types.f32, &[]); - push_builtin_impl(tcx.types.f64, &[]); } ty::Projection(_projection_ty) => { @@ -216,7 +215,10 @@ crate fn assemble_builtin_sized_impls<'tcx>( ty::Opaque(..) => (), ty::Bound(..) | - ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty), + ty::GeneratorWitness(..) | + ty::Infer(ty::FreshTy(_)) | + ty::Infer(ty::FreshIntTy(_)) | + ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), } } @@ -243,7 +245,9 @@ crate fn assemble_builtin_copy_clone_impls<'tcx>( ty::Never | ty::Ref(_, _, hir::MutImmutable) => (), - // Non parametric primitive type. + // Non parametric primitive types. + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) | ty::Error => push_builtin_impl(ty, &[]), // These implement `Copy`/`Clone` if their element types do. @@ -283,13 +287,11 @@ crate fn assemble_builtin_copy_clone_impls<'tcx>( // These depend on whatever user-defined impls might exist. ty::Adt(_, _) => (), - // int vars and float vars are always `Copy`. - // Other vars will trigger an ambiguity. - ty::Infer(..) => { + // Artificially trigger an ambiguity by adding two possible types to + // unify against. + ty::Infer(ty::TyVar(_)) => { push_builtin_impl(tcx.types.i32, &[]); - push_builtin_impl(tcx.types.u32, &[]); push_builtin_impl(tcx.types.f32, &[]); - push_builtin_impl(tcx.types.f64, &[]); } ty::Projection(_projection_ty) => { @@ -312,6 +314,9 @@ crate fn assemble_builtin_copy_clone_impls<'tcx>( ty::Ref(_, _, hir::MutMutable) => (), ty::Bound(..) | - ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty), + ty::GeneratorWitness(..) | + ty::Infer(ty::FreshTy(_)) | + ty::Infer(ty::FreshIntTy(_)) | + ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), } } From 4bd36ab64cae41e89d53113f683d790210846c1f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 24 Apr 2019 06:39:40 +0200 Subject: [PATCH 12/22] Introduce hir::ExprKind::Use and employ in for loop desugaring. Here, ExprKind::Use(P) tweaks the drop order to act the same way as '{ let _tmp = expr; _tmp }' does. --- src/librustc/cfg/construct.rs | 1 + src/librustc/hir/intravisit.rs | 3 ++ src/librustc/hir/lowering.rs | 45 +++++++------------ src/librustc/hir/mod.rs | 6 +++ src/librustc/hir/print.rs | 53 +++++++++++++++++------ src/librustc/lib.rs | 1 + src/librustc/middle/expr_use_visitor.rs | 4 ++ src/librustc/middle/liveness.rs | 8 ++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/region.rs | 6 +++ src/librustc_mir/hair/cx/expr.rs | 3 ++ src/librustc_passes/rvalue_promotion.rs | 9 ++-- src/librustc_typeck/check/mod.rs | 3 ++ 13 files changed, 92 insertions(+), 52 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index e96709f6d14e5..8a4594fe0e89e 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -369,6 +369,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprKind::AddrOf(_, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Use(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Field(ref e, _) | hir::ExprKind::Yield(ref e) | diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index a0c9e5983a1d7..3d727f7cd9128 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1029,6 +1029,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } + ExprKind::Use(ref subexpression) => { + visitor.visit_expr(subexpression); + } ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); visitor.visit_expr(if_block); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 380dee5fcdcc2..37373da72fbd6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4738,16 +4738,11 @@ impl<'a> LoweringContext<'a> { hir::MatchSource::ForLoopDesugar, )); - // `{ let _result = ...; _result }` - // Underscore prevents an `unused_variables` lint if the head diverges. - let result_ident = self.str_to_ident("_result"); - let (let_stmt, let_stmt_binding) = - self.stmt_let(e.span, false, result_ident, match_expr); - - let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); - let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); - // Add the attributes to the outer returned expr node. - return self.expr_block(block, e.attrs.clone()); + // This is effectively `{ let _result = ...; _result }`. + // The construct was introduced in #21984. + // FIXME(60253): Is this still necessary? + // Also, add the attributes to the outer returned expr node. + return self.expr_use(head_sp, match_expr, e.attrs.clone()) } // Desugar `ExprKind::Try` @@ -5117,6 +5112,17 @@ impl<'a> LoweringContext<'a> { ) } + /// Wrap the given `expr` in `hir::ExprKind::Use`. + /// + /// In terms of drop order, it has the same effect as + /// wrapping `expr` in `{ let _t = $expr; _t }` but + /// should provide better compile-time performance. + /// + /// The drop order can be important in e.g. `if expr { .. }`. + fn expr_use(&mut self, span: Span, expr: P, attrs: ThinVec) -> hir::Expr { + self.expr(span, hir::ExprKind::Use(expr), attrs) + } + fn expr_match( &mut self, span: Span, @@ -5172,25 +5178,6 @@ impl<'a> LoweringContext<'a> { } } - fn stmt_let( - &mut self, - sp: Span, - mutbl: bool, - ident: Ident, - ex: P, - ) -> (hir::Stmt, hir::HirId) { - let (pat, pat_hid) = if mutbl { - self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable) - } else { - self.pat_ident(sp, ident) - }; - - ( - self.stmt_let_pat(sp, Some(ex), pat, hir::LocalSource::Normal), - pat_hid, - ) - } - fn block_expr(&mut self, expr: P) -> hir::Block { self.block_all(expr.span, hir::HirVec::new(), Some(expr)) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f114f0fc23695..2e10300dced0e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1366,6 +1366,7 @@ impl Expr { ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, + ExprKind::Use(ref expr, ..) => expr.precedence(), ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, ExprKind::Loop(..) => ExprPrecedence::Loop, @@ -1437,6 +1438,7 @@ impl Expr { ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::Cast(..) | + ExprKind::Use(..) | ExprKind::Err => { false } @@ -1486,6 +1488,10 @@ pub enum ExprKind { Cast(P, P), /// A type reference (e.g., `Foo`). Type(P, P), + /// Semantically equivalent to `{ let _t = expr; _t }`. + /// Maps directly to `hair::ExprKind::Use`. + /// Only exists to tweak the drop order in HIR. + Use(P), /// An `if` block, with an optional else block. /// /// I.e., `if { } else { }`. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index dc87e13b739d6..06225364f6c70 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -995,23 +995,32 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ii.hir_id)) } + pub fn print_local( + &mut self, + init: Option<&hir::Expr>, + decl: impl Fn(&mut Self) -> io::Result<()> + ) -> io::Result<()> { + self.space_if_not_bol()?; + self.ibox(indent_unit)?; + self.word_nbsp("let")?; + + self.ibox(indent_unit)?; + decl(self)?; + self.end()?; + + if let Some(ref init) = init { + self.nbsp()?; + self.word_space("=")?; + self.print_expr(&init)?; + } + self.end() + } + pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> { self.maybe_print_comment(st.span.lo())?; match st.node { hir::StmtKind::Local(ref loc) => { - self.space_if_not_bol()?; - self.ibox(indent_unit)?; - self.word_nbsp("let")?; - - self.ibox(indent_unit)?; - self.print_local_decl(&loc)?; - self.end()?; - if let Some(ref init) = loc.init { - self.nbsp()?; - self.word_space("=")?; - self.print_expr(&init)?; - } - self.end()? + self.print_local(loc.init.deref(), |this| this.print_local_decl(&loc))?; } hir::StmtKind::Item(item) => { self.ann.nested(self, Nested::Item(item))? @@ -1379,6 +1388,24 @@ impl<'a> State<'a> { self.word_space(":")?; self.print_type(&ty)?; } + hir::ExprKind::Use(ref init) => { + // Print `{`: + self.cbox(indent_unit)?; + self.ibox(0)?; + self.bopen()?; + + // Print `let _t = $init;`: + let temp = ast::Ident::from_str("_t"); + self.print_local(Some(init), |this| this.print_ident(temp))?; + self.s.word(";")?; + + // Print `_t`: + self.space_if_not_bol()?; + self.print_ident(temp)?; + + // Print `}`: + self.bclose_maybe_open(expr.span, indent_unit, true)?; + } hir::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bd44b13b669c..920f978054396 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -37,6 +37,7 @@ #![feature(box_syntax)] #![feature(core_intrinsics)] #![feature(drain_filter)] +#![feature(inner_deref)] #![cfg_attr(windows, feature(libc))] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 217af7eea9685..52f105b8c40e5 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -521,6 +521,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } + hir::ExprKind::Use(ref expr) => { + self.consume_expr(&expr); + } + hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b8cde936bded3..966bec8381ae7 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -521,6 +521,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Binary(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(_) | @@ -1221,6 +1222,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::AddrOf(_, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Use(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Yield(ref e) | hir::ExprKind::Repeat(ref e, _) => { @@ -1524,9 +1526,9 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Index(..) | hir::ExprKind::Field(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | - hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) | - hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) | - hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | + hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) | + hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | + hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a4a54ba18371a..25fa19558de97 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -678,7 +678,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) | - hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) | hir::ExprKind::Binary(..) | hir::ExprKind::While(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2b3802388106a..9a5af8a25378f 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -909,6 +909,12 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: visitor.cx.var_parent = visitor.cx.parent; } + hir::ExprKind::Use(ref expr) => { + // `Use(expr)` does not denote a conditional scope. + // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. + terminating(expr.hir_id.local_id); + } + hir::ExprKind::AssignOp(..) | hir::ExprKind::Index(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => { // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 7ab3341127546..e54a24f4df197 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -759,6 +759,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } + hir::ExprKind::Use(ref source) => { + ExprKind::Use { source: source.to_ref() } + } hir::ExprKind::Box(ref value) => { ExprKind::Box { value: value.to_ref(), diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index e2c5c4ee3746d..2a423cc41661a 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -436,7 +436,9 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Err => Promotable, hir::ExprKind::AddrOf(_, ref expr) | - hir::ExprKind::Repeat(ref expr, _) => { + hir::ExprKind::Repeat(ref expr, _) | + hir::ExprKind::Type(ref expr, _) | + hir::ExprKind::Use(ref expr) => { v.check_expr(&expr) } @@ -483,10 +485,6 @@ fn check_expr_kind<'a, 'tcx>( array_result } - hir::ExprKind::Type(ref expr, ref _ty) => { - v.check_expr(&expr) - } - hir::ExprKind::Tup(ref hirvec) => { let mut tup_result = Promotable; for index in hirvec.iter() { @@ -495,7 +493,6 @@ fn check_expr_kind<'a, 'tcx>( tup_result } - // Conditional control flow (possible to implement). hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => { // Compute the most demanding borrow from all the arms' diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bd715df6e9d1e..ff3245a467ad8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4533,6 +4533,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_eq_type(&e, ty); ty } + ExprKind::Use(ref e) => { + self.check_expr_with_expectation(e, expected) + } ExprKind::Array(ref args) => { let uty = expected.to_option(self).and_then(|uty| { match uty.sty { From 6aa5a5df965db2d6f567fe34a316b5f4e0234c15 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Apr 2019 13:20:43 +0200 Subject: [PATCH 13/22] Improvement comment explanations --- src/librustdoc/html/render.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 703f7b18d160e..bd74789b65bd2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1319,8 +1319,11 @@ fn write_minify_replacer( f, "R", Token::Char(ReservedChar::Backline), - // This closure prevents crates' name to be aggregated. It allows to not - // have to look for crate's name into the strings array. + // This closure prevents crates' names from being aggregated. + // + // The point here is to check if the string is preceded by '[' and + // "searchIndex". If so, it means this is a crate name and that it + // shouldn't be aggregated. |tokens, pos| { pos < 2 || !tokens[pos - 1].is_char(ReservedChar::OpenBracket) || From 72cda98e48e41d5852b4746688cc85d56c22f982 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 24 Apr 2019 19:21:10 -0300 Subject: [PATCH 14/22] Implement Debug for Place using Place::iterate --- src/librustc/mir/mod.rs | 138 +++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 52 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index bf2a1eaafd664..3d094e72d26aa 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2156,61 +2156,95 @@ impl<'p, 'tcx> FusedIterator for PlaceProjectionsIter<'p, 'tcx> {} impl<'tcx> Debug for Place<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - use self::Place::*; - - match *self { - Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id), - Base(PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) })) => { - write!( - fmt, - "({}: {:?})", - ty::tls::with(|tcx| tcx.def_path_str(def_id)), - ty - ) - }, - Base(PlaceBase::Static( - box self::Static { ty, kind: StaticKind::Promoted(promoted) }) - ) => { - write!( - fmt, - "({:?}: {:?})", - promoted, - ty - ) - }, - Projection(ref data) => match data.elem { - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, "({:?} as {})", data.base, name) - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, "({:?} as variant#{:?})", data.base, index) - } - ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base), - ProjectionElem::Field(field, ty) => { - write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty) - } - ProjectionElem::Index(ref index) => write!(fmt, "{:?}[{:?}]", data.base, index), - ProjectionElem::ConstantIndex { - offset, - min_length, - from_end: false, - } => write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::ConstantIndex { - offset, - min_length, - from_end: true, - } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::Subslice { from, to } if to == 0 => { - write!(fmt, "{:?}[{:?}:]", data.base, from) + self.iterate(|_place_base, place_projections| { + // FIXME: remove this collect once we have migrated to slices + let projs_vec: Vec<_> = place_projections.collect(); + for projection in projs_vec.iter().rev() { + match projection.elem { + ProjectionElem::Downcast(_, _) | + ProjectionElem::Field(_, _) => { + write!(fmt, "(").unwrap(); + } + ProjectionElem::Deref => { + write!(fmt, "(*").unwrap(); + } + ProjectionElem::Index(_) | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Subslice { .. } => {} } - ProjectionElem::Subslice { from, to } if from == 0 => { - write!(fmt, "{:?}[:-{:?}]", data.base, to) + } + }); + + self.iterate(|place_base, place_projections| { + match place_base { + PlaceBase::Local(id) => { + write!(fmt, "{:?}", id)?; } - ProjectionElem::Subslice { from, to } => { - write!(fmt, "{:?}[{:?}:-{:?}]", data.base, from, to) + PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => { + write!( + fmt, + "({}: {:?})", + ty::tls::with(|tcx| tcx.def_path_str(*def_id)), + ty + )?; + }, + PlaceBase::Static( + box self::Static { ty, kind: StaticKind::Promoted(promoted) } + ) => { + write!( + fmt, + "({:?}: {:?})", + promoted, + ty + )?; + }, + } + + for projection in place_projections { + match projection.elem { + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, " as {})", name)?; + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, " as variant#{:?})", index)?; + } + ProjectionElem::Deref => { + write!(fmt, ")")?; + } + ProjectionElem::Field(field, ty) => { + write!(fmt, ".{:?}: {:?})", field.index(), ty)?; + } + ProjectionElem::Index(ref index) => { + write!(fmt, "[{:?}]", index)?; + } + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end: false, + } => { + write!(fmt, "[{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end: true, + } => { + write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::Subslice { from, to } if to == 0 => { + write!(fmt, "[{:?}:]", from)?; + } + ProjectionElem::Subslice { from, to } if from == 0 => { + write!(fmt, "[:-{:?}]", to)?; + } + ProjectionElem::Subslice { from, to } => { + write!(fmt, "[{:?}:-{:?}]", from, to)?; + } } - }, - } + } + + Ok(()) + }) } } From d37f3fc1ecb453e8c38ca9bcf90e43192fccb797 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 25 Apr 2019 15:44:22 +0200 Subject: [PATCH 15/22] Add feature-gate for f16c target feature --- src/libsyntax/feature_gate.rs | 1 + src/test/ui/target-feature-gate.rs | 1 + src/test/ui/target-feature-gate.stderr | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ba567a123aec1..e90564d5aa5b1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -403,6 +403,7 @@ declare_features! ( (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), (active, movbe_target_feature, "1.34.0", Some(44839), None), (active, rtm_target_feature, "1.35.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), // Allows macro invocations on modules expressions and statements and // procedural macros to expand to non-items. diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs index 8f3a52ba5d677..bc7f7caa10766 100644 --- a/src/test/ui/target-feature-gate.rs +++ b/src/test/ui/target-feature-gate.rs @@ -24,6 +24,7 @@ // gate-test-cmpxchg16b_target_feature // gate-test-movbe_target_feature // gate-test-rtm_target_feature +// gate-test-f16c_target_feature // min-llvm-version 6.0 #[target_feature(enable = "avx512bw")] diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr index e142125225fb4..c7adba868eaf8 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature-gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/target-feature-gate.rs:29:18 + --> $DIR/target-feature-gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ From 976b3d1d9ebde26f32a3a58731d68e8edcc01962 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 25 Apr 2019 21:11:46 +0100 Subject: [PATCH 16/22] Prevent const parameters having type parameters as types --- src/librustc_resolve/error_codes.rs | 10 +++++++ src/librustc_resolve/lib.rs | 44 +++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 5c095994a1bbd..d3b66ddb4a7b4 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1642,6 +1642,16 @@ fn main() { ``` "##, +E0671: r##" +Const parameters cannot depend on type parameters. +The following is therefore invalid: +``` +fn const_id() -> T { + N +} +``` +"##, + } register_diagnostics! { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7754bb26f9055..80b82bc4dbd84 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -185,6 +185,8 @@ enum ResolutionError<'a> { BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) + /// Error E0671: const parameter cannot depend on type parameter. + ConstParamDependentOnTypeParam, } /// Combines an error with provided span and emits it. @@ -440,6 +442,16 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, span, "defaulted type parameters cannot be forward declared".to_string()); err } + ResolutionError::ConstParamDependentOnTypeParam => { + let mut err = struct_span_err!( + resolver.session, + span, + E0671, + "const parameters cannot depend on type parameters" + ); + err.span_label(span, format!("const parameter depends on type parameter")); + err + } } } @@ -915,6 +927,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { } })); + // We also ban access to type parameters for use as the types of const parameters. + let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); + const_ty_param_ban_rib.bindings.extend(generics.params.iter() + .filter(|param| { + if let GenericParamKind::Type { .. } = param.kind { + true + } else { + false + } + }) + .map(|param| (Ident::with_empty_ctxt(param.ident.name), Def::Err))); + for param in &generics.params { match param.kind { GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), @@ -933,11 +957,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name)); } GenericParamKind::Const { ref ty } => { + self.ribs[TypeNS].push(const_ty_param_ban_rib); + for bound in ¶m.bounds { self.visit_param_bound(bound); } self.visit_ty(ty); + + const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap(); } } } @@ -994,6 +1022,9 @@ enum RibKind<'a> { /// from the default of a type parameter because they're not declared /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, + + /// We forbid the use of type parameters as the types of const parameters. + TyParamAsConstParamTy, } /// A single local scope. @@ -3944,6 +3975,15 @@ impl<'a> Resolver<'a> { return Def::Err; } + // An invalid use of a type parameter as the type of a const parameter. + if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind { + if record_used { + resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam); + } + assert_eq!(def, Def::Err); + return Def::Err; + } + match def { Def::Upvar(..) => { span_bug!(span, "unexpected {:?} in bindings", def) @@ -3955,7 +3995,7 @@ impl<'a> Resolver<'a> { for rib in ribs { match rib.kind { NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) | - ForwardTyParamBanRibKind => { + ForwardTyParamBanRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } ClosureRibKind(function_id) => { @@ -4013,7 +4053,7 @@ impl<'a> Resolver<'a> { match rib.kind { NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind | - ConstantItemRibKind => { + ConstantItemRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } ItemRibKind | FnItemRibKind => { From 102f7a8b26a549f095f7d075eae37189be2bdd5a Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 25 Apr 2019 21:12:03 +0100 Subject: [PATCH 17/22] Make sure const params with type params don't cause errors without a feature gate --- ...aram-type-depends-on-type-param-ungated.rs | 6 ++++++ ...-type-depends-on-type-param-ungated.stderr | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs create mode 100644 src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs new file mode 100644 index 0000000000000..af5e8f49754e8 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -0,0 +1,6 @@ +use std::marker::PhantomData; + +struct B(PhantomData<[T; N]>); //~ ERROR const generics are unstable +//~^ ERROR const parameters cannot depend on type parameters + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr new file mode 100644 index 0000000000000..e3adbcfe60204 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -0,0 +1,19 @@ +error[E0671]: const parameters cannot depend on type parameters + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 + | +LL | struct B(PhantomData<[T; N]>); + | ^ const parameter depends on type parameter + +error[E0658]: const generics are unstable + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 + | +LL | struct B(PhantomData<[T; N]>); + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0671. +For more information about an error, try `rustc --explain E0658`. From 908a6399bcbc008a6d3b36b3db8724d7c93e890f Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 25 Apr 2019 21:12:17 +0100 Subject: [PATCH 18/22] Add a test for const parameters with type parameters as types --- .../const-param-type-depends-on-type-param.rs | 7 ++++++ ...st-param-type-depends-on-type-param.stderr | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/ui/const-generics/const-param-type-depends-on-type-param.rs create mode 100644 src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs new file mode 100644 index 0000000000000..ca924695993ca --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -0,0 +1,7 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub struct Dependent([(); X]); //~ ERROR const parameters +//~^ ERROR parameter `T` is never used + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr new file mode 100644 index 0000000000000..0722c2c99fe07 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -0,0 +1,24 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-type-depends-on-type-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0671]: const parameters cannot depend on type parameters + --> $DIR/const-param-type-depends-on-type-param.rs:4:34 + | +LL | pub struct Dependent([(); X]); + | ^ const parameter depends on type parameter + +error[E0392]: parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:4:22 + | +LL | pub struct Dependent([(); X]); + | ^ unused parameter + | + = help: consider removing `T` or using a marker such as `std::marker::PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0392, E0671. +For more information about an error, try `rustc --explain E0392`. From 6b190d6de5e34bcb3e66d088dd0503c6810d357b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 25 Apr 2019 13:16:21 -0700 Subject: [PATCH 19/22] Do not ICE when checking types against foreign fn --- src/librustc_typeck/check/op.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 78ce0bf9cc16b..d1ca05780930a 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -443,13 +443,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ) -> bool /* did we suggest to call a function because of missing parenthesis? */ { err.span_label(span, ty.to_string()); if let FnDef(def_id, _) = ty.sty { + let source_map = self.tcx.sess.source_map(); + let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return false, + }; if self.tcx.has_typeck_tables(def_id) == false { return false; } - let source_map = self.tcx.sess.source_map(); - let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap(); let fn_sig = { - match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) { + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { Some(f) => f.clone(), None => { bug!("No fn-sig entry for def_id={:?}", def_id); @@ -458,11 +461,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; let other_ty = if let FnDef(def_id, _) = other_ty.sty { + let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return false, + }; if self.tcx.has_typeck_tables(def_id) == false { return false; } - let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap(); - match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) { + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { Some(f) => f.clone().output(), None => { bug!("No fn-sig entry for def_id={:?}", def_id); From 0a26789af90a78558144db0dbedeb820f07f2a61 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 25 Apr 2019 14:03:45 -0700 Subject: [PATCH 20/22] Make `-Z allow-features` work for stdlib features --- src/libsyntax/feature_gate.rs | 34 +++++++++---------- .../ui/feature-gate/allow-features-empty.rs | 2 ++ .../feature-gate/allow-features-empty.stderr | 8 ++++- src/test/ui/feature-gate/allow-features.rs | 2 ++ .../ui/feature-gate/allow-features.stderr | 8 ++++- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ba567a123aec1..5a92e7fefab6c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2258,32 +2258,32 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], continue; } - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|f| *f == name.as_str()).is_none() { - span_err!(span_handler, mi.span(), E0725, - "the feature `{}` is not in the list of allowed features", - name); - continue; - } - } - - set(&mut features, mi.span()); - features.declared_lang_features.push((name, mi.span(), None)); - continue - } - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); if let Some((.., reason)) = removed.or(stable_removed) { feature_removed(span_handler, mi.span(), *reason); - continue + continue; } if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { let since = Some(Symbol::intern(since)); features.declared_lang_features.push((name, mi.span(), since)); - continue + continue; + } + + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|f| *f == name.as_str()).is_none() { + span_err!(span_handler, mi.span(), E0725, + "the feature `{}` is not in the list of allowed features", + name); + continue; + } + } + + if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { + set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; } features.declared_lib_features.push((name, mi.span())); diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs index 83250052cb506..784a1d2697d67 100644 --- a/src/test/ui/feature-gate/allow-features-empty.rs +++ b/src/test/ui/feature-gate/allow-features-empty.rs @@ -7,4 +7,6 @@ #![feature(lang_items)] //~ ERROR +#![feature(unknown_stdlib_feature)] //~ ERROR + fn main() {} diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr index cce2c4078c242..ab41422ed05b8 100644 --- a/src/test/ui/feature-gate/allow-features-empty.stderr +++ b/src/test/ui/feature-gate/allow-features-empty.stderr @@ -16,6 +16,12 @@ error[E0725]: the feature `lang_items` is not in the list of allowed features LL | #![feature(lang_items)] | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features + --> $DIR/allow-features-empty.rs:10:12 + | +LL | #![feature(unknown_stdlib_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0725`. diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs index 1cebc8f34f26f..de3439a5b628f 100644 --- a/src/test/ui/feature-gate/allow-features.rs +++ b/src/test/ui/feature-gate/allow-features.rs @@ -7,4 +7,6 @@ #![feature(lang_items)] +#![feature(unknown_stdlib_feature)] //~ ERROR + fn main() {} diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr index b13560fb81c6a..5b39a6f053bde 100644 --- a/src/test/ui/feature-gate/allow-features.stderr +++ b/src/test/ui/feature-gate/allow-features.stderr @@ -4,6 +4,12 @@ error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed f LL | #![feature(rustc_const_unstable)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features + --> $DIR/allow-features.rs:10:12 + | +LL | #![feature(unknown_stdlib_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0725`. From 8f78736feeb03cc64c54197881032a996ff8a6b3 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 25 Apr 2019 23:19:36 +0100 Subject: [PATCH 21/22] Fix error code description --- src/librustc_resolve/error_codes.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index d3b66ddb4a7b4..7cd26dce1447c 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1645,8 +1645,11 @@ fn main() { E0671: r##" Const parameters cannot depend on type parameters. The following is therefore invalid: -``` -fn const_id() -> T { +```compile_fail,E0671 +#![feature(const_generics)] + +fn const_id() -> T { // error: const parameter + // depends on type parameter N } ``` From 6d7c7940b581e8a7f311327e9b48203ce97b8137 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 25 Apr 2019 23:29:58 +0100 Subject: [PATCH 22/22] Add comment explaining restriction --- .../const-param-type-depends-on-type-param.rs | 10 ++++++++-- .../const-param-type-depends-on-type-param.stderr | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs index ca924695993ca..28e0d6c2bb7e7 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -1,7 +1,13 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -pub struct Dependent([(); X]); //~ ERROR const parameters -//~^ ERROR parameter `T` is never used +// Currently, const parameters cannot depend on type parameters, because there is no way to +// enforce the `structural_match` property on an arbitrary type parameter. This restriction +// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more +// details. + +pub struct Dependent([(); X]); +//~^ ERROR const parameters cannot depend on type parameters +//~^^ ERROR parameter `T` is never used fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index 0722c2c99fe07..c7dcbe1354266 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -5,13 +5,13 @@ LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ error[E0671]: const parameters cannot depend on type parameters - --> $DIR/const-param-type-depends-on-type-param.rs:4:34 + --> $DIR/const-param-type-depends-on-type-param.rs:9:34 | LL | pub struct Dependent([(); X]); | ^ const parameter depends on type parameter error[E0392]: parameter `T` is never used - --> $DIR/const-param-type-depends-on-type-param.rs:4:22 + --> $DIR/const-param-type-depends-on-type-param.rs:9:22 | LL | pub struct Dependent([(); X]); | ^ unused parameter