From 9568ec6bef514515b14c78c7492186d509048968 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Tue, 11 Sep 2018 22:55:26 -0700 Subject: [PATCH 01/18] Move conditional configuration related UI tests into their own directory --- .../{ => conditional-compilation}/auxiliary/namespaced_enums.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-1.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-2.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-3.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-4.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-5.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-attr-cfg-2.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-attr-cfg-2.stderr | 0 src/test/ui/{ => conditional-compilation}/cfg-attr-crate-2.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-attr-crate-2.stderr | 0 .../{ => conditional-compilation}/cfg-attr-invalid-predicate.rs | 0 .../cfg-attr-invalid-predicate.stderr | 0 .../{ => conditional-compilation}/cfg-attr-syntax-validation.rs | 0 .../cfg-attr-syntax-validation.stderr | 0 .../cfg-attr-unknown-attribute-macro-expansion.rs | 0 .../cfg-attr-unknown-attribute-macro-expansion.stderr | 0 src/test/ui/{ => conditional-compilation}/cfg-empty-codemap.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-in-crate-1.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-in-crate-1.stderr | 0 src/test/ui/{ => conditional-compilation}/cfg-non-opt-expr.rs | 0 src/test/ui/{ => conditional-compilation}/cfg-non-opt-expr.stderr | 0 src/test/ui/{ => conditional-compilation}/cfg_attr_path.rs | 0 src/test/ui/{ => conditional-compilation}/cfg_attr_path.stderr | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => conditional-compilation}/auxiliary/namespaced_enums.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-1.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-2.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-3.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-4.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-arg-invalid-5.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-cfg-2.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-cfg-2.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-crate-2.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-crate-2.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-invalid-predicate.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-invalid-predicate.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-syntax-validation.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-syntax-validation.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-unknown-attribute-macro-expansion.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-attr-unknown-attribute-macro-expansion.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg-empty-codemap.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-in-crate-1.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-in-crate-1.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg-non-opt-expr.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg-non-opt-expr.stderr (100%) rename src/test/ui/{ => conditional-compilation}/cfg_attr_path.rs (100%) rename src/test/ui/{ => conditional-compilation}/cfg_attr_path.stderr (100%) diff --git a/src/test/ui/auxiliary/namespaced_enums.rs b/src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs similarity index 100% rename from src/test/ui/auxiliary/namespaced_enums.rs rename to src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs diff --git a/src/test/ui/cfg-arg-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-1.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs diff --git a/src/test/ui/cfg-arg-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-2.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs diff --git a/src/test/ui/cfg-arg-invalid-3.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-3.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs diff --git a/src/test/ui/cfg-arg-invalid-4.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-4.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs diff --git a/src/test/ui/cfg-arg-invalid-5.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-5.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs diff --git a/src/test/ui/cfg-attr-cfg-2.rs b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs similarity index 100% rename from src/test/ui/cfg-attr-cfg-2.rs rename to src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs diff --git a/src/test/ui/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr similarity index 100% rename from src/test/ui/cfg-attr-cfg-2.stderr rename to src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr diff --git a/src/test/ui/cfg-attr-crate-2.rs b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs similarity index 100% rename from src/test/ui/cfg-attr-crate-2.rs rename to src/test/ui/conditional-compilation/cfg-attr-crate-2.rs diff --git a/src/test/ui/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr similarity index 100% rename from src/test/ui/cfg-attr-crate-2.stderr rename to src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr diff --git a/src/test/ui/cfg-attr-invalid-predicate.rs b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs similarity index 100% rename from src/test/ui/cfg-attr-invalid-predicate.rs rename to src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs diff --git a/src/test/ui/cfg-attr-invalid-predicate.stderr b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr similarity index 100% rename from src/test/ui/cfg-attr-invalid-predicate.stderr rename to src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr diff --git a/src/test/ui/cfg-attr-syntax-validation.rs b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs similarity index 100% rename from src/test/ui/cfg-attr-syntax-validation.rs rename to src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs diff --git a/src/test/ui/cfg-attr-syntax-validation.stderr b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr similarity index 100% rename from src/test/ui/cfg-attr-syntax-validation.stderr rename to src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs similarity index 100% rename from src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs rename to src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr similarity index 100% rename from src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr rename to src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr diff --git a/src/test/ui/cfg-empty-codemap.rs b/src/test/ui/conditional-compilation/cfg-empty-codemap.rs similarity index 100% rename from src/test/ui/cfg-empty-codemap.rs rename to src/test/ui/conditional-compilation/cfg-empty-codemap.rs diff --git a/src/test/ui/cfg-in-crate-1.rs b/src/test/ui/conditional-compilation/cfg-in-crate-1.rs similarity index 100% rename from src/test/ui/cfg-in-crate-1.rs rename to src/test/ui/conditional-compilation/cfg-in-crate-1.rs diff --git a/src/test/ui/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr similarity index 100% rename from src/test/ui/cfg-in-crate-1.stderr rename to src/test/ui/conditional-compilation/cfg-in-crate-1.stderr diff --git a/src/test/ui/cfg-non-opt-expr.rs b/src/test/ui/conditional-compilation/cfg-non-opt-expr.rs similarity index 100% rename from src/test/ui/cfg-non-opt-expr.rs rename to src/test/ui/conditional-compilation/cfg-non-opt-expr.rs diff --git a/src/test/ui/cfg-non-opt-expr.stderr b/src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr similarity index 100% rename from src/test/ui/cfg-non-opt-expr.stderr rename to src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr diff --git a/src/test/ui/cfg_attr_path.rs b/src/test/ui/conditional-compilation/cfg_attr_path.rs similarity index 100% rename from src/test/ui/cfg_attr_path.rs rename to src/test/ui/conditional-compilation/cfg_attr_path.rs diff --git a/src/test/ui/cfg_attr_path.stderr b/src/test/ui/conditional-compilation/cfg_attr_path.stderr similarity index 100% rename from src/test/ui/cfg_attr_path.stderr rename to src/test/ui/conditional-compilation/cfg_attr_path.stderr From 1a867dc346a0b9ea5abd8a8504f1908f42ff2dd2 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Mon, 10 Sep 2018 15:06:49 -0700 Subject: [PATCH 02/18] cfg_attr_multi: Basic implementation Does not implement the warning or a feature flag. --- src/libsyntax/config.rs | 59 ++++++++++++++----- src/libsyntax/parse/parser.rs | 2 +- src/test/ui/cfg-attr-trailing-comma.rs | 13 ---- src/test/ui/cfg-attr-trailing-comma.stderr | 14 ----- .../cfg-attr-crate-2.stderr | 2 +- .../cfg-attr-multi-false.rs | 19 ++++++ .../cfg-attr-multi-invalid-1.rs | 15 +++++ .../cfg-attr-multi-invalid-1.stderr | 11 ++++ .../cfg-attr-multi-invalid-2.rs | 15 +++++ .../cfg-attr-multi-invalid-2.stderr | 11 ++++ .../cfg-attr-multi-true.rs | 21 +++++++ .../cfg-attr-multi-true.stderr | 38 ++++++++++++ .../conditional-compilation/cfg-attr-parse.rs | 45 ++++++++++++++ .../cfg-attr-parse.stderr | 32 ++++++++++ 14 files changed, 252 insertions(+), 45 deletions(-) delete mode 100644 src/test/ui/cfg-attr-trailing-comma.rs delete mode 100644 src/test/ui/cfg-attr-trailing-comma.stderr create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-false.rs create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-true.rs create mode 100644 src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr create mode 100644 src/test/ui/conditional-compilation/cfg-attr-parse.rs create mode 100644 src/test/ui/conditional-compilation/cfg-attr-parse.stderr diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a9ce236557779..7a85f62853641 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -73,49 +73,76 @@ impl<'a> StripUnconfigured<'a> { if self.in_cfg(node.attrs()) { Some(node) } else { None } } + /// Parse and expand all `cfg_attr` attributes into a list of attributes + /// that are within each `cfg_attr` that has a true configuration predicate. + /// + /// Gives compiler warnigns if any `cfg_attr` does not contain any + /// attributes and is in the original source code. Gives compiler errors if + /// the syntax of any `cfg_attr` is incorrect. pub fn process_cfg_attrs(&mut self, node: T) -> T { node.map_attrs(|attrs| { - attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect() }) } - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option { + /// Parse and expand a single `cfg_attr` attribute into a list of attributes + /// when the configuration predicate is true, or otherwise expand into an + /// empty list of attributes. + /// + /// Gives a compiler warning when the `cfg_attr` contains no attribtes and + /// is in the original source file. Gives a compiler error if the syntax of + /// the attribute is incorrect + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { if !attr.check_name("cfg_attr") { - return Some(attr); + return vec![attr]; } - let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| { + let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { parser.expect(&token::OpenDelim(token::Paren))?; - let cfg = parser.parse_meta_item()?; + + let cfg_predicate = parser.parse_meta_item()?; parser.expect(&token::Comma)?; - let lo = parser.span.lo(); - let (path, tokens) = parser.parse_meta_item_unrestricted()?; - parser.eat(&token::Comma); // Optional trailing comma + + // Presumably, the majority of the time there will only be one attr. + let mut expanded_attrs = Vec::with_capacity(1); + + while !parser.check(&token::CloseDelim(token::Paren)) { + let lo = parser.span.lo(); + let (path, tokens) = parser.parse_meta_item_unrestricted()?; + expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); + parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + } + parser.expect(&token::CloseDelim(token::Paren))?; - Ok((cfg, path, tokens, parser.prev_span.with_lo(lo))) + Ok((cfg_predicate, expanded_attrs)) }) { Ok(result) => result, Err(mut e) => { e.emit(); - return None; + return Vec::new(); } }; - if attr::cfg_matches(&cfg, self.sess, self.features) { - self.process_cfg_attr(ast::Attribute { + if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs.into_iter() + .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { id: attr::mk_attr_id(), style: attr.style, path, tokens, is_sugared_doc: false, span, - }) + })) + .collect() } else { - None + Vec::new() } } - // Determine if a node with the given attributes should be included in this configuration. + /// Determine if a node with the given attributes should be included in this configuration. pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { if !is_cfg(attr) { @@ -165,7 +192,7 @@ impl<'a> StripUnconfigured<'a> { }) } - // Visit attributes on expression and statements (but not attributes on items in blocks). + /// Visit attributes on expression and statements (but not attributes on items in blocks). fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { // flag the offending attributes for attr in attrs.iter() { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5571a18b59625..a5ee2b0f10353 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -678,7 +678,7 @@ impl<'a> Parser<'a> { /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. - fn expect_one_of(&mut self, + pub fn expect_one_of(&mut self, edible: &[token::Token], inedible: &[token::Token]) -> PResult<'a, ()>{ fn tokens_to_string(tokens: &[TokenType]) -> String { diff --git a/src/test/ui/cfg-attr-trailing-comma.rs b/src/test/ui/cfg-attr-trailing-comma.rs deleted file mode 100644 index 21e00544ca00b..0000000000000 --- a/src/test/ui/cfg-attr-trailing-comma.rs +++ /dev/null @@ -1,13 +0,0 @@ -// compile-flags: --cfg TRUE - -#[cfg_attr(TRUE, inline,)] // OK -fn f() {} - -#[cfg_attr(FALSE, inline,)] // OK -fn g() {} - -#[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,` -fn h() {} - -#[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,` -fn i() {} diff --git a/src/test/ui/cfg-attr-trailing-comma.stderr b/src/test/ui/cfg-attr-trailing-comma.stderr deleted file mode 100644 index 76a470417e9ed..0000000000000 --- a/src/test/ui/cfg-attr-trailing-comma.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: expected `)`, found `,` - --> $DIR/cfg-attr-trailing-comma.rs:9:25 - | -LL | #[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,` - | ^ expected `)` - -error: expected `)`, found `,` - --> $DIR/cfg-attr-trailing-comma.rs:12:26 - | -LL | #[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,` - | ^ expected `)` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr index 7b66c8f5e40f0..a730473f66315 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr @@ -2,7 +2,7 @@ error[E0658]: no_core is experimental (see issue #29639) --> $DIR/cfg-attr-crate-2.rs:15:21 | LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental - | ^^^^^^^^ + | ^^^^^^^ | = help: add #![feature(no_core)] to the crate attributes to enable diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs new file mode 100644 index 0000000000000..ff7a47e083940 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs @@ -0,0 +1,19 @@ +// Test that cfg_attr doesn't emit any attributes when the +// configuation variable is false. This mirrors `cfg-attr-multi-true.rs` + +// compile-pass + +#![warn(unused_must_use)] + +#[cfg_attr(any(), deprecated, must_use)] +struct Struct {} + +impl Struct { + fn new() -> Struct { + Struct {} + } +} + +fn main() { + Struct::new(); +} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs new file mode 100644 index 0000000000000..a9ddbf7d80d3e --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// compile-flags: --cfg broken + +#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental + +fn main() { } diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr new file mode 100644 index 0000000000000..344a05a4fecbb --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -0,0 +1,11 @@ +error[E0658]: no_core is experimental (see issue #29639) + --> $DIR/cfg-attr-multi-invalid-1.rs:13:21 + | +LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental + | ^^^^^^^ + | + = help: add #![feature(no_core)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs new file mode 100644 index 0000000000000..211eb08f08e28 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// compile-flags: --cfg broken + +#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental + +fn main() { } diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr new file mode 100644 index 0000000000000..54854d2e29d53 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -0,0 +1,11 @@ +error[E0658]: no_core is experimental (see issue #29639) + --> $DIR/cfg-attr-multi-invalid-2.rs:13:29 + | +LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental + | ^^^^^^^ + | + = help: add #![feature(no_core)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs new file mode 100644 index 0000000000000..4b9a8d46b9b1f --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs @@ -0,0 +1,21 @@ +// Test that cfg_attr with multiple attributes actually emits both attributes. +// This is done by emitting two attributes that cause new warnings, and then +// triggering those warnings. + +// compile-pass + +#![warn(unused_must_use)] + +#[cfg_attr(all(), deprecated, must_use)] +struct MustUseDeprecated {} + +impl MustUseDeprecated { //~ warning: use of deprecated item + fn new() -> MustUseDeprecated { //~ warning: use of deprecated item + MustUseDeprecated {} //~ warning: use of deprecated item + } +} + +fn main() { + MustUseDeprecated::new(); //~ warning: use of deprecated item + //| warning: unused `MustUseDeprecated` which must be used +} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr new file mode 100644 index 0000000000000..21634ee4f26b8 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr @@ -0,0 +1,38 @@ +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:12:6 + | +LL | impl MustUseDeprecated { //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^ + | + = note: #[warn(deprecated)] on by default + +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:19:5 + | +LL | MustUseDeprecated::new(); //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:13:17 + | +LL | fn new() -> MustUseDeprecated { //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:14:9 + | +LL | MustUseDeprecated {} //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^ + +warning: unused `MustUseDeprecated` which must be used + --> $DIR/cfg-attr-multi-true.rs:19:5 + | +LL | MustUseDeprecated::new(); //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/cfg-attr-multi-true.rs:7:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs new file mode 100644 index 0000000000000..eec0e8faca877 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs @@ -0,0 +1,45 @@ +// Parse `cfg_attr` with varying numbers of attributes and trailing commas + +#![feature(cfg_attr_multi)] + +// Completely empty `cfg_attr` input +#[cfg_attr()] //~ error: expected identifier, found `)` +struct NoConfigurationPredicate; + +// Zero attributes, zero trailing comma (comma manatory here) +#[cfg_attr(all())] //~ error: expected `,`, found `)` +struct A0C0; + +// Zero attributes, one trailing comma +#[cfg_attr(all(),)] // Ok +struct A0C1; + +// Zero attributes, two trailing commas +#[cfg_attr(all(),,)] //~ ERROR expected identifier +struct A0C2; + +// One attribute, no trailing comma +#[cfg_attr(all(), must_use)] // Ok +struct A1C0; + +// One attribute, one trailing comma +#[cfg_attr(all(), must_use,)] // Ok +struct A1C1; + +// One attribute, two trailing commas +#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier +struct A1C2; + +// Two attributes, no trailing comma +#[cfg_attr(all(), must_use, deprecated)] // Ok +struct A2C0; + +// Two attributes, one trailing comma +#[cfg_attr(all(), must_use, deprecated,)] // Ok +struct A2C1; + +// Two attributes, two trailing commas +#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier +struct A2C2; + +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr new file mode 100644 index 0000000000000..553406b6dd83d --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr @@ -0,0 +1,32 @@ +error: expected identifier, found `)` + --> $DIR/cfg-attr-parse.rs:6:12 + | +LL | #[cfg_attr()] //~ error: expected identifier, found `)` + | ^ expected identifier + +error: expected `,`, found `)` + --> $DIR/cfg-attr-parse.rs:10:17 + | +LL | #[cfg_attr(all())] //~ error: expected `,`, found `)` + | ^ expected `,` + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:18:18 + | +LL | #[cfg_attr(all(),,)] //~ ERROR expected identifier + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:30:28 + | +LL | #[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:42:40 + | +LL | #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier + | ^ expected identifier + +error: aborting due to 5 previous errors + From 35e6c65628a537ad92a38b562a6f9e2de1887b5b Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Thu, 4 Oct 2018 04:55:47 -0700 Subject: [PATCH 03/18] cfg_attr_multi: Feature gate --- .../src/language-features/cfg-attr-multi.md | 20 +++++++++++ src/libsyntax/config.rs | 36 ++++++++++++++++++- src/libsyntax/feature_gate.rs | 3 ++ .../cfg-attr-multi-false.rs | 1 + .../cfg-attr-multi-invalid-1.rs | 1 + .../cfg-attr-multi-invalid-1.stderr | 2 +- .../cfg-attr-multi-invalid-2.rs | 1 + .../cfg-attr-multi-invalid-2.stderr | 2 +- .../cfg-attr-multi-true.rs | 1 + .../cfg-attr-multi-true.stderr | 10 +++--- .../feature-gate-cfg-attr-multi-1.rs | 5 +++ .../feature-gate-cfg-attr-multi-1.stderr | 11 ++++++ .../feature-gate-cfg-attr-multi-2.rs | 3 ++ .../feature-gate-cfg-attr-multi-2.stderr | 11 ++++++ ...feature-gate-cfg-attr-multi-bootstrap-1.rs | 7 ++++ ...feature-gate-cfg-attr-multi-bootstrap-2.rs | 9 +++++ 16 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/cfg-attr-multi.md create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs diff --git a/src/doc/unstable-book/src/language-features/cfg-attr-multi.md b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md new file mode 100644 index 0000000000000..759a28c4f5fdd --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md @@ -0,0 +1,20 @@ +# `cfg_attr_multi` + +The tracking issue for this feature is: [#555666] +The RFC for this feature is: [#2539] + +[#555666]: https://github.com/rust-lang/rust/issues/555666 +[#2539]: https://github.com/rust-lang/rfcs/pull/2539 + +------------------------ + +This feature flag lets you put multiple attributes into a `cfg_attr` attribute. + +Example: + +```rust,ignore +#[cfg_attr(all(), must_use, optimize)] +``` + +Because `cfg_attr` resolves before procedural macros, this does not affect +macro resolution at all. \ No newline at end of file diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 7a85f62853641..e611eb86dc1b3 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -9,7 +9,14 @@ // except according to those terms. use attr::HasAttrs; -use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; +use feature_gate::{ + feature_err, + EXPLAIN_STMT_ATTR_SYNTAX, + Features, + get_features, + GateIssue, + emit_feature_err, +}; use {fold, attr}; use ast; use source_map::Spanned; @@ -97,6 +104,13 @@ impl<'a> StripUnconfigured<'a> { return vec![attr]; } + let gate_cfg_attr_multi = if let Some(ref features) = self.features { + !features.cfg_attr_multi + } else { + false + }; + let cfg_attr_span = attr.span; + let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { parser.expect(&token::OpenDelim(token::Paren))?; @@ -123,6 +137,26 @@ impl<'a> StripUnconfigured<'a> { } }; + // Check feature gate and lint on zero attributes in source. Even if the feature is gated, + // we still compute as if it wasn't, since the emitted error will stop compilation futher + // along the compilation. + match (expanded_attrs.len(), gate_cfg_attr_multi) { + (0, false) => { + // FIXME: Emit unused attribute lint here. + }, + (1, _) => {}, + (_, true) => { + emit_feature_err( + self.sess, + "cfg_attr_multi", + cfg_attr_span, + GateIssue::Language, + "cfg_attr with zero or more than one attributes is experimental", + ); + }, + (_, false) => {} + } + if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { // We call `process_cfg_attr` recursively in case there's a // `cfg_attr` inside of another `cfg_attr`. E.g. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index adbe2f9d4393f..7707bbaa8b0e0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -515,6 +515,9 @@ declare_features! ( // Allows `impl Trait` in bindings (`let`, `const`, `static`) (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), + + // #[cfg_attr(predicate, multiple, attributes, here)] + (active, cfg_attr_multi, "1.31.0", Some(555666), None), ); declare_features! ( diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs index ff7a47e083940..84bd33fc0e7d3 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs @@ -4,6 +4,7 @@ // compile-pass #![warn(unused_must_use)] +#![feature(cfg_attr_multi)] #[cfg_attr(any(), deprecated, must_use)] struct Struct {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs index a9ddbf7d80d3e..d4c3186a6ebbb 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs @@ -10,6 +10,7 @@ // // compile-flags: --cfg broken +#![feature(cfg_attr_multi)] #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental fn main() { } diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr index 344a05a4fecbb..bf68d92cc0bbd 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -1,5 +1,5 @@ error[E0658]: no_core is experimental (see issue #29639) - --> $DIR/cfg-attr-multi-invalid-1.rs:13:21 + --> $DIR/cfg-attr-multi-invalid-1.rs:14:21 | LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental | ^^^^^^^ diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs index 211eb08f08e28..bee6b7d4886bd 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs @@ -10,6 +10,7 @@ // // compile-flags: --cfg broken +#![feature(cfg_attr_multi)] #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental fn main() { } diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr index 54854d2e29d53..5c72a400e0bae 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -1,5 +1,5 @@ error[E0658]: no_core is experimental (see issue #29639) - --> $DIR/cfg-attr-multi-invalid-2.rs:13:29 + --> $DIR/cfg-attr-multi-invalid-2.rs:14:29 | LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental | ^^^^^^^ diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs index 4b9a8d46b9b1f..a31dde00c7cf5 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs @@ -5,6 +5,7 @@ // compile-pass #![warn(unused_must_use)] +#![feature(cfg_attr_multi)] #[cfg_attr(all(), deprecated, must_use)] struct MustUseDeprecated {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr index 21634ee4f26b8..37cb3de06c04f 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr @@ -1,5 +1,5 @@ warning: use of deprecated item 'MustUseDeprecated' - --> $DIR/cfg-attr-multi-true.rs:12:6 + --> $DIR/cfg-attr-multi-true.rs:13:6 | LL | impl MustUseDeprecated { //~ warning: use of deprecated item | ^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | impl MustUseDeprecated { //~ warning: use of deprecated item = note: #[warn(deprecated)] on by default warning: use of deprecated item 'MustUseDeprecated' - --> $DIR/cfg-attr-multi-true.rs:19:5 + --> $DIR/cfg-attr-multi-true.rs:20:5 | LL | MustUseDeprecated::new(); //~ warning: use of deprecated item | ^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'MustUseDeprecated' - --> $DIR/cfg-attr-multi-true.rs:13:17 + --> $DIR/cfg-attr-multi-true.rs:14:17 | LL | fn new() -> MustUseDeprecated { //~ warning: use of deprecated item | ^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'MustUseDeprecated' - --> $DIR/cfg-attr-multi-true.rs:14:9 + --> $DIR/cfg-attr-multi-true.rs:15:9 | LL | MustUseDeprecated {} //~ warning: use of deprecated item | ^^^^^^^^^^^^^^^^^ warning: unused `MustUseDeprecated` which must be used - --> $DIR/cfg-attr-multi-true.rs:19:5 + --> $DIR/cfg-attr-multi-true.rs:20:5 | LL | MustUseDeprecated::new(); //~ warning: use of deprecated item | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs new file mode 100644 index 0000000000000..9515380bc2856 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs @@ -0,0 +1,5 @@ +// gate-test-cfg_attr_multi + +#![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))] +//~^ ERROR cfg_attr with zero or more than one attributes is experimental +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr new file mode 100644 index 0000000000000..23c09c913f430 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr @@ -0,0 +1,11 @@ +error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #555666) + --> $DIR/feature-gate-cfg-attr-multi-1.rs:3:1 + | +LL | #![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(cfg_attr_multi)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs new file mode 100644 index 0000000000000..cf02432274b1e --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs @@ -0,0 +1,3 @@ +#![cfg_attr(all(),)] +//~^ ERROR cfg_attr with zero or more than one attributes is experimental +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr new file mode 100644 index 0000000000000..d8f4acd12d722 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr @@ -0,0 +1,11 @@ +error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #555666) + --> $DIR/feature-gate-cfg-attr-multi-2.rs:1:1 + | +LL | #![cfg_attr(all(),)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(cfg_attr_multi)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs new file mode 100644 index 0000000000000..e4737926e7a22 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs @@ -0,0 +1,7 @@ +// Test that settingt the featute gate while using its functionality doesn't error. + +// compile-pass + +#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")] + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs new file mode 100644 index 0000000000000..df740541f5543 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs @@ -0,0 +1,9 @@ +// Test that settingt the featute gate while using its functionality doesn't error. +// Specifically, if there's a cfg-attr *before* the feature gate. + +// compile-pass + +#![cfg_attr(all(),)] +#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")] + +fn main() {} From b7248d5988ae4a4498fd900482142151e3ddddd2 Mon Sep 17 00:00:00 2001 From: Donato Sciarra Date: Sun, 7 Oct 2018 00:05:42 +0200 Subject: [PATCH 04/18] Fix internal compiler error on malformed match arm pattern. Issue: 54379 --- src/libsyntax/parse/parser.rs | 3 +++ src/test/ui/resolve/issue-54379.rs | 21 +++++++++++++++++++++ src/test/ui/resolve/issue-54379.stderr | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/test/ui/resolve/issue-54379.rs create mode 100644 src/test/ui/resolve/issue-54379.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d653ed819fddd..03decd584514d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3866,6 +3866,9 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { let err = self.struct_span_err(self.prev_span, "expected `,`"); + if let Some(mut delayed) = delayed_err { + delayed.emit(); + } return Err(err); } ate_comma = false; diff --git a/src/test/ui/resolve/issue-54379.rs b/src/test/ui/resolve/issue-54379.rs new file mode 100644 index 0000000000000..24aa758ea6c23 --- /dev/null +++ b/src/test/ui/resolve/issue-54379.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +struct MyStruct { + pub s1: Option, +} + +fn main() { + let thing = MyStruct { s1: None }; + + match thing { + MyStruct { .., Some(_) } => {}, + _ => {} + } +} diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr new file mode 100644 index 0000000000000..d1d693a3817b9 --- /dev/null +++ b/src/test/ui/resolve/issue-54379.stderr @@ -0,0 +1,24 @@ +error: expected `}`, found `,` + --> $DIR/issue-54379.rs:18:22 + | +LL | MyStruct { .., Some(_) } => {}, + | --^ + | | | + | | expected `}` + | `..` must be at the end and cannot have a trailing comma + +error: expected `,` + --> $DIR/issue-54379.rs:18:24 + | +LL | MyStruct { .., Some(_) } => {}, + | ^^^^ + +error[E0027]: pattern does not mention field `s1` + --> $DIR/issue-54379.rs:18:9 + | +LL | MyStruct { .., Some(_) } => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0027`. From 91b71f5e9416b570b3e4c1997056c3879e5029af Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 5 Oct 2018 17:05:33 +0200 Subject: [PATCH 05/18] Identify borrows captured by trait objects. This commit enhances `LaterUseKind` detection to identify when a borrow is captured by a trait object which helps explain why there is a borrow error. --- .../borrow_check/nll/explain_borrow/mod.rs | 173 ++++++++++++++---- ...ons-close-over-type-parameter-2.nll.stderr | 2 +- 2 files changed, 137 insertions(+), 38 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index e55469436abf0..74bbdebe7a3ad 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -13,8 +13,10 @@ use borrow_check::error_reporting::UseSpans; use borrow_check::nll::region_infer::Cause; use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; use rustc::ty::{self, Region, TyCtxt}; -use rustc::mir::{FakeReadCause, Local, Location, Mir, Operand}; -use rustc::mir::{Place, StatementKind, TerminatorKind}; +use rustc::mir::{ + FakeReadCause, Local, Location, Mir, Operand, Place, Rvalue, Statement, StatementKind, + TerminatorKind +}; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -34,6 +36,7 @@ pub(in borrow_check) enum BorrowExplanation<'tcx> { #[derive(Clone, Copy)] pub(in borrow_check) enum LaterUseKind { + TraitCapture, ClosureCapture, Call, FakeLetRead, @@ -51,6 +54,7 @@ impl<'tcx> BorrowExplanation<'tcx> { match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => { let message = match later_use_kind { + LaterUseKind::TraitCapture => "borrow later captured here by trait object", LaterUseKind::ClosureCapture => "borrow later captured here by closure", LaterUseKind::Call => "borrow later used by call", LaterUseKind::FakeLetRead => "borrow later stored here", @@ -60,9 +64,10 @@ impl<'tcx> BorrowExplanation<'tcx> { }, BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { let message = match later_use_kind { - LaterUseKind::ClosureCapture => { - "borrow captured here by closure, in later iteration of loop" - }, + LaterUseKind::TraitCapture => + "borrow later captured here by trait object, in later iteration of loop", + LaterUseKind::ClosureCapture => + "borrow captured here by closure, in later iteration of loop", LaterUseKind::Call => "borrow used by call, in later iteration of loop", LaterUseKind::FakeLetRead => "borrow later stored here", LaterUseKind::Other => "borrow used here, in later iteration of loop", @@ -200,13 +205,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .or_else(|| self.borrow_spans(span, location)); if self.is_borrow_location_in_loop(context.loc) { - let later_use = self.later_use_kind(spans, location); + let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = ` patterns. - let later_use = self.later_use_kind(spans, location); + let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLater(later_use.0, later_use.1) } } @@ -316,42 +321,136 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { false } - fn later_use_kind(&self, use_spans: UseSpans, location: Location) -> (LaterUseKind, Span) { - use self::LaterUseKind::*; - - let block = &self.mir.basic_blocks()[location.block]; + /// Determine how the borrow was later used. + fn later_use_kind( + &self, + borrow: &BorrowData<'tcx>, + use_spans: UseSpans, + location: Location + ) -> (LaterUseKind, Span) { match use_spans { - UseSpans::ClosureUse { var_span, .. } => (LaterUseKind::ClosureCapture, var_span), + UseSpans::ClosureUse { var_span, .. } => { + // Used in a closure. + (LaterUseKind::ClosureCapture, var_span) + }, UseSpans::OtherUse(span) => { - (if let Some(stmt) = block.statements.get(location.statement_index) { - match stmt.kind { - StatementKind::FakeRead(FakeReadCause::ForLet, _) => FakeLetRead, - _ => Other, + let block = &self.mir.basic_blocks()[location.block]; + + let kind = if let Some(&Statement { + kind: StatementKind::FakeRead(FakeReadCause::ForLet, _), + .. + }) = block.statements.get(location.statement_index) { + LaterUseKind::FakeLetRead + } else if self.was_captured_by_trait_object(borrow) { + LaterUseKind::TraitCapture + } else if location.statement_index == block.statements.len() { + if let TerminatorKind::Call { + ref func, from_hir_call: true, .. + } = block.terminator().kind { + // Just point to the function, to reduce the chance of overlapping spans. + let function_span = match func { + Operand::Constant(c) => c.span, + Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => { + let local_decl = &self.mir.local_decls[*l]; + if local_decl.name.is_none() { + local_decl.source_info.span + } else { + span + } + }, + _ => span, + }; + return (LaterUseKind::Call, function_span); + } else { + LaterUseKind::Other } } else { - assert_eq!(location.statement_index, block.statements.len()); - match block.terminator().kind { - TerminatorKind::Call { ref func, from_hir_call: true, .. } => { - // Just point to the function, to reduce the chance - // of overlapping spans. - let function_span = match func { - Operand::Constant(c) => c.span, - Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => { - let local_decl = &self.mir.local_decls[*l]; - if local_decl.name.is_none() { - local_decl.source_info.span - } else { - span - } - }, - _ => span, - }; - return (Call, function_span); - }, - _ => Other, + LaterUseKind::Other + }; + + (kind, span) + } + } + } + + /// Check if a borrowed value was captured by a trait object. + fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { + // In order to check if a value was captured by a trait object, we want to look through + // statements after the reserve location in the current block. We expect the reserve + // location to be a statement assigning to a local. We follow that local in the subsequent + // statements, checking for an assignment of our local (or something intermediate that + // it was assigned into) that results in a trait object. + let location = borrow.reserve_location; + let block = &self.mir[location.block]; + let stmt = block.statements.get(location.statement_index); + debug!( + "was_captured_by_trait_object: location={:?} block={:?} stmt={:?}", + location, block, stmt + ); + let mut target = if let Some(&Statement { + kind: StatementKind::Assign(Place::Local(local), _), + .. + }) = stmt { + local + } else { + return false; + }; + + debug!("was_captured_by_trait_object: target={:?}", target); + for stmt in &block.statements[location.statement_index + 1..] { + debug!("was_captured_by_trait_object: stmt={:?}", stmt); + // Simple case where our target is assigned into another local, and we start + // watching that local instead. + if let StatementKind::Assign( + Place::Local(into), + box Rvalue::Use(operand), + ) = &stmt.kind { + debug!("was_captured_by_trait_object: target={:?} operand={:?}", target, operand); + match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => target = *into, + _ => {}, + } + } + } + + if let Some(terminator) = &block.terminator { + if let TerminatorKind::Call { + destination: Some((Place::Local(dest), _)), + args, + .. + } = &terminator.kind { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + let mut found_target = false; + for arg in args { + if let Operand::Move(Place::Local(potential)) = arg { + if *potential == target { + found_target = true; + } + } + } + + if found_target { + let local_decl_ty = &self.mir.local_decls[*dest].ty; + debug!("was_captured_by_trait_object: local_decl_ty={:?}", local_decl_ty); + match local_decl_ty.sty { + // `&dyn Trait` + ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, + // `Box` + _ if local_decl_ty.is_box() && local_decl_ty.boxed_ty().is_trait() => + return true, + // `dyn Trait` + _ if local_decl_ty.is_trait() => return true, + // Anything else. + _ => return false, } - }, span) + } } } + + false } } diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr index f8e5e3914eb3c..11fa447b5489a 100644 --- a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr +++ b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr @@ -4,7 +4,7 @@ error[E0597]: `tmp0` does not live long enough LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | repeater3(tmp1) - | --------------- borrow later used here + | --------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed From 72911fbbd051c1824f00735ac1b57017ca709a87 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 5 Oct 2018 23:31:33 +0200 Subject: [PATCH 06/18] Update logic to search for casts. This commit updates the captured trait object search logic to look for unsized casts to boxed types rather than for functions that returned trait objects. --- .../borrow_check/nll/explain_borrow/mod.rs | 170 +++++++++++------- src/test/ui/nll/issue-52663-trait-object.rs | 27 +++ .../ui/nll/issue-52663-trait-object.stderr | 13 ++ 3 files changed, 149 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/nll/issue-52663-trait-object.rs create mode 100644 src/test/ui/nll/issue-52663-trait-object.stderr diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 74bbdebe7a3ad..307112f8ba16a 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -14,8 +14,8 @@ use borrow_check::nll::region_infer::Cause; use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; use rustc::ty::{self, Region, TyCtxt}; use rustc::mir::{ - FakeReadCause, Local, Location, Mir, Operand, Place, Rvalue, Statement, StatementKind, - TerminatorKind + CastKind, FakeReadCause, Local, Location, Mir, Operand, Place, Projection, ProjectionElem, + Rvalue, Statement, StatementKind, TerminatorKind }; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -65,7 +65,7 @@ impl<'tcx> BorrowExplanation<'tcx> { BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { let message = match later_use_kind { LaterUseKind::TraitCapture => - "borrow later captured here by trait object, in later iteration of loop", + "borrow captured here by trait object, in later iteration of loop", LaterUseKind::ClosureCapture => "borrow captured here by closure, in later iteration of loop", LaterUseKind::Call => "borrow used by call, in later iteration of loop", @@ -373,20 +373,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - /// Check if a borrowed value was captured by a trait object. + /// Check if a borrowed value was captured by a trait object. We do this by + /// looking forward in the MIR from the reserve location and checking if we see + /// a unsized cast to a trait object on our data. fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { - // In order to check if a value was captured by a trait object, we want to look through - // statements after the reserve location in the current block. We expect the reserve - // location to be a statement assigning to a local. We follow that local in the subsequent - // statements, checking for an assignment of our local (or something intermediate that - // it was assigned into) that results in a trait object. + // Start at the reserve location, find the place that we want to see cast to a trait object. let location = borrow.reserve_location; let block = &self.mir[location.block]; let stmt = block.statements.get(location.statement_index); - debug!( - "was_captured_by_trait_object: location={:?} block={:?} stmt={:?}", - location, block, stmt - ); + debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt); + + // We make a `queue` vector that has the locations we want to visit. As of writing, this + // will only ever have one item at any given time, but by using a vector, we can pop from + // it which simplifies the termination logic. + let mut queue = vec![location]; let mut target = if let Some(&Statement { kind: StatementKind::Assign(Place::Local(local), _), .. @@ -396,61 +396,109 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return false; }; - debug!("was_captured_by_trait_object: target={:?}", target); - for stmt in &block.statements[location.statement_index + 1..] { - debug!("was_captured_by_trait_object: stmt={:?}", stmt); - // Simple case where our target is assigned into another local, and we start - // watching that local instead. - if let StatementKind::Assign( - Place::Local(into), - box Rvalue::Use(operand), - ) = &stmt.kind { - debug!("was_captured_by_trait_object: target={:?} operand={:?}", target, operand); - match operand { - Operand::Copy(Place::Local(from)) | - Operand::Move(Place::Local(from)) if *from == target => target = *into, - _ => {}, - } - } - } - - if let Some(terminator) = &block.terminator { - if let TerminatorKind::Call { - destination: Some((Place::Local(dest), _)), - args, - .. - } = &terminator.kind { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - let mut found_target = false; - for arg in args { - if let Operand::Move(Place::Local(potential)) = arg { - if *potential == target { - found_target = true; - } + debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); + while let Some(current_location) = queue.pop() { + debug!("was_captured_by_trait: target={:?}", target); + let block = &self.mir[current_location.block]; + // We need to check the current location to find out if it is a terminator. + let is_terminator = current_location.statement_index == block.statements.len(); + if !is_terminator { + let stmt = &block.statements[current_location.statement_index]; + debug!("was_captured_by_trait_object: stmt={:?}", stmt); + + // The only kind of statement that we care about is assignments... + if let StatementKind::Assign( + place, + box rvalue, + ) = &stmt.kind { + let into = match place { + Place::Local(into) => into, + Place::Projection(box Projection { + base: Place::Local(into), + elem: ProjectionElem::Deref, + }) => into, + _ => { + // Continue at the next location. + queue.push(current_location.successor_within_block()); + continue; + }, + }; + + match rvalue { + // If we see a use, we should check whether it is our data, and if so + // update the place that we're looking for to that new place. + Rvalue::Use(operand) => match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => { + target = *into; + }, + _ => {}, + }, + // If we see a unsized cast, then if it is our data we should check + // whether it is being cast to a trait object. + Rvalue::Cast(CastKind::Unsize, operand, ty) => match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => { + debug!("was_captured_by_trait_object: ty={:?}", ty); + // Check the type for a trait object. + match ty.sty { + // `&dyn Trait` + ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, + // `Box` + _ if ty.is_box() && ty.boxed_ty().is_trait() => + return true, + // `dyn Trait` + _ if ty.is_trait() => return true, + // Anything else. + _ => return false, + } + }, + _ => return false, + }, + _ => {}, } } - if found_target { - let local_decl_ty = &self.mir.local_decls[*dest].ty; - debug!("was_captured_by_trait_object: local_decl_ty={:?}", local_decl_ty); - match local_decl_ty.sty { - // `&dyn Trait` - ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, - // `Box` - _ if local_decl_ty.is_box() && local_decl_ty.boxed_ty().is_trait() => - return true, - // `dyn Trait` - _ if local_decl_ty.is_trait() => return true, - // Anything else. - _ => return false, - } + // Continue at the next location. + queue.push(current_location.successor_within_block()); + } else { + // The only thing we need to do for terminators is progress to the next block. + let terminator = block.terminator(); + debug!("was_captured_by_trait_object: terminator={:?}", terminator); + + match &terminator.kind { + TerminatorKind::Call { + destination: Some((Place::Local(dest), block)), + args, + .. + } => { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(Place::Local(potential)) = arg { + *potential == target + } else { + false + } + }); + + // If it is, follow this to the next block and update the target. + if found_target { + target = *dest; + queue.push(block.start_location()); + } + }, + _ => {}, } } + + debug!("was_captured_by_trait: queue={:?}", queue); } + // We didn't find anything and ran out of locations to check. false } } diff --git a/src/test/ui/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs new file mode 100644 index 0000000000000..65d73eeae67c4 --- /dev/null +++ b/src/test/ui/nll/issue-52663-trait-object.rs @@ -0,0 +1,27 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] +#![feature(nll)] + +trait Foo { fn get(&self); } + +impl Foo for A { + fn get(&self) { } +} + +fn main() { + let _ = { + let tmp0 = 3; + let tmp1 = &tmp0; + box tmp1 as Box + }; + //~^^^ ERROR `tmp0` does not live long enough +} diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr new file mode 100644 index 0000000000000..035422f245825 --- /dev/null +++ b/src/test/ui/nll/issue-52663-trait-object.stderr @@ -0,0 +1,13 @@ +error[E0597]: `tmp0` does not live long enough + --> $DIR/issue-52663-trait-object.rs:23:20 + | +LL | let tmp1 = &tmp0; + | ^^^^^ borrowed value does not live long enough +LL | box tmp1 as Box + | ------------------------- borrow later captured here by trait object +LL | }; + | - `tmp0` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From bbe832d570e826b2012c09869aa77d6201932730 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Sun, 7 Oct 2018 21:48:28 -0700 Subject: [PATCH 07/18] cfg-attr-multi: Change issue number to actual tracking issue --- src/doc/unstable-book/src/language-features/cfg-attr-multi.md | 4 ++-- src/libsyntax/feature_gate.rs | 2 +- .../ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr | 2 +- .../ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/cfg-attr-multi.md b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md index 759a28c4f5fdd..6365d3e71c616 100644 --- a/src/doc/unstable-book/src/language-features/cfg-attr-multi.md +++ b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md @@ -1,9 +1,9 @@ # `cfg_attr_multi` -The tracking issue for this feature is: [#555666] +The tracking issue for this feature is: [#54881] The RFC for this feature is: [#2539] -[#555666]: https://github.com/rust-lang/rust/issues/555666 +[#54881]: https://github.com/rust-lang/rust/issues/54881 [#2539]: https://github.com/rust-lang/rfcs/pull/2539 ------------------------ diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7707bbaa8b0e0..276b0623a1fff 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -517,7 +517,7 @@ declare_features! ( (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), // #[cfg_attr(predicate, multiple, attributes, here)] - (active, cfg_attr_multi, "1.31.0", Some(555666), None), + (active, cfg_attr_multi, "1.31.0", Some(54881), None), ); declare_features! ( diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr index 23c09c913f430..088e6df1a1ac1 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr @@ -1,4 +1,4 @@ -error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #555666) +error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881) --> $DIR/feature-gate-cfg-attr-multi-1.rs:3:1 | LL | #![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr index d8f4acd12d722..a01876114dde8 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #555666) +error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881) --> $DIR/feature-gate-cfg-attr-multi-2.rs:1:1 | LL | #![cfg_attr(all(),)] From 8c01c225ce1fd2b28817f6ea72d29e218f0f8a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Mon, 8 Oct 2018 10:06:45 +0200 Subject: [PATCH 08/18] Stabilize the `Option::replace` method --- src/libcore/option.rs | 4 +--- src/libcore/tests/lib.rs | 1 - src/librustc_driver/lib.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0255f7a0885ea..ee313cd6e8e97 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -867,8 +867,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(option_replace)] - /// /// let mut x = Some(2); /// let old = x.replace(5); /// assert_eq!(x, Some(5)); @@ -880,7 +878,7 @@ impl Option { /// assert_eq!(old, None); /// ``` #[inline] - #[unstable(feature = "option_replace", issue = "51998")] + #[stable(feature = "option_replace", since = "1.30.0")] pub fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index ada61d8dfd873..0beb60a127097 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -39,7 +39,6 @@ #![feature(reverse_bits)] #![feature(inner_deref)] #![feature(slice_internals)] -#![feature(option_replace)] #![feature(slice_partition_dedup)] #![feature(copy_within)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4405c0aef9023..0514bd20c985a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -21,7 +21,6 @@ #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(option_replace)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] From c232ea12763b82ae8d4b616df649c23c4961d0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Mon, 8 Oct 2018 10:18:43 +0200 Subject: [PATCH 09/18] Bump the `Option::replace` stabilize version to 1.31.0 --- src/libcore/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index ee313cd6e8e97..cf1c77041b91f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -878,7 +878,7 @@ impl Option { /// assert_eq!(old, None); /// ``` #[inline] - #[stable(feature = "option_replace", since = "1.30.0")] + #[stable(feature = "option_replace", since = "1.31.0")] pub fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } From 663002f22267569ae300308837fcf684d8147d32 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 6 Oct 2018 13:51:02 +0200 Subject: [PATCH 10/18] Pass around interned refs to goals and not goals --- src/Cargo.lock | 8 ++--- src/librustc/Cargo.toml | 2 +- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/traits/mod.rs | 22 +++++++------ src/librustc/traits/structural_impls.rs | 34 ++++++++++---------- src/librustc/ty/context.rs | 29 +++++++++-------- src/librustc_traits/Cargo.toml | 2 +- src/librustc_traits/chalk_context.rs | 41 +++++++++++++------------ src/librustc_traits/lowering.rs | 21 ++++++++----- 9 files changed, 88 insertions(+), 73 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 6a9488226b1bd..2719587f20e8a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chalk-engine" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1898,7 +1898,7 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", @@ -2434,7 +2434,7 @@ name = "rustc_traits" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -3195,7 +3195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" -"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0" +"checksum chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6749eb72e7d4355d944a99f15fbaea701b978c18c5e184a025fcde942b0c9779" "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 6c3b52196a3a2..d0ec8640ce9ef 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -31,7 +31,7 @@ syntax_pos = { path = "../libsyntax_pos" } backtrace = "0.3.3" parking_lot = "0.6" byteorder = { version = "1.1", features = ["i128"]} -chalk-engine = { version = "0.7.0", default-features=false } +chalk-engine = { version = "0.8.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.5", features = ["union"] } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 3ff0034fbbee7..d6666c8793ecb 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1356,7 +1356,7 @@ impl<'a, 'tcx> HashStable> for traits::Goal<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use traits::Goal::*; + use traits::GoalKind::*; mem::discriminant(self).hash_stable(hcx, hasher); match self { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 286e35c5d4e95..6e4abee32c077 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -318,31 +318,33 @@ pub enum QuantifierKind { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Goal<'tcx> { - Implies(Clauses<'tcx>, &'tcx Goal<'tcx>), - And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>), - Not(&'tcx Goal<'tcx>), +pub enum GoalKind<'tcx> { + Implies(Clauses<'tcx>, Goal<'tcx>), + And(Goal<'tcx>, Goal<'tcx>), + Not(Goal<'tcx>), DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>), + Quantified(QuantifierKind, ty::Binder>), CannotProve, } +pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; + pub type Goals<'tcx> = &'tcx List>; impl<'tcx> DomainGoal<'tcx> { - pub fn into_goal(self) -> Goal<'tcx> { - Goal::DomainGoal(self) + pub fn into_goal(self) -> GoalKind<'tcx> { + GoalKind::DomainGoal(self) } } -impl<'tcx> Goal<'tcx> { +impl<'tcx> GoalKind<'tcx> { pub fn from_poly_domain_goal<'a>( domain_goal: PolyDomainGoal<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - ) -> Goal<'tcx> { + ) -> GoalKind<'tcx> { match domain_goal.no_late_bound_regions() { Some(p) => p.into_goal(), - None => Goal::Quantified( + None => GoalKind::Quantified( QuantifierKind::Universal, domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())) ), diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 22e79fc2638ab..1524f89af291d 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -469,7 +469,7 @@ impl fmt::Display for traits::QuantifierKind { impl<'tcx> fmt::Display for traits::Goal<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use traits::Goal::*; + use traits::GoalKind::*; match self { Implies(hypotheses, goal) => { @@ -598,25 +598,25 @@ CloneTypeFoldableAndLiftImpls! { } EnumTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { - (traits::Goal::Implies)(hypotheses, goal), - (traits::Goal::And)(goal1, goal2), - (traits::Goal::Not)(goal), - (traits::Goal::DomainGoal)(domain_goal), - (traits::Goal::Quantified)(qkind, goal), - (traits::Goal::CannotProve), + impl<'tcx> TypeFoldable<'tcx> for traits::GoalKind<'tcx> { + (traits::GoalKind::Implies)(hypotheses, goal), + (traits::GoalKind::And)(goal1, goal2), + (traits::GoalKind::Not)(goal), + (traits::GoalKind::DomainGoal)(domain_goal), + (traits::GoalKind::Quantified)(qkind, goal), + (traits::GoalKind::CannotProve), } } EnumLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for traits::Goal<'a> { - type Lifted = traits::Goal<'tcx>; - (traits::Goal::Implies)(hypotheses, goal), - (traits::Goal::And)(goal1, goal2), - (traits::Goal::Not)(goal), - (traits::Goal::DomainGoal)(domain_goal), - (traits::Goal::Quantified)(kind, goal), - (traits::Goal::CannotProve), + impl<'a, 'tcx> Lift<'tcx> for traits::GoalKind<'a> { + type Lifted = traits::GoalKind<'tcx>; + (traits::GoalKind::Implies)(hypotheses, goal), + (traits::GoalKind::And)(goal1, goal2), + (traits::GoalKind::Not)(goal), + (traits::GoalKind::DomainGoal)(domain_goal), + (traits::GoalKind::Quantified)(kind, goal), + (traits::GoalKind::CannotProve), } } @@ -633,7 +633,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx traits::Goal<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let v = (**self).fold_with(folder); folder.tcx().mk_goal(v) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 46ba5f5ef362d..3d4ae572d0b81 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -36,7 +36,7 @@ use mir::interpret::Allocation; use ty::subst::{CanonicalSubsts, Kind, Substs, Subst}; use ty::ReprOptions; use traits; -use traits::{Clause, Clauses, Goal, Goals}; +use traits::{Clause, Clauses, GoalKind, Goal, Goals}; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TyKind, List}; use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const}; @@ -143,7 +143,8 @@ pub struct CtxtInterners<'tcx> { predicates: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, clauses: InternedSet<'tcx, List>>, - goals: InternedSet<'tcx, List>>, + goal: InternedSet<'tcx, GoalKind<'tcx>>, + goal_list: InternedSet<'tcx, List>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { @@ -159,7 +160,8 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { predicates: Default::default(), const_: Default::default(), clauses: Default::default(), - goals: Default::default(), + goal: Default::default(), + goal_list: Default::default(), } } @@ -1731,9 +1733,9 @@ impl<'a, 'tcx> Lift<'tcx> for Region<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for &'a Goal<'a> { - type Lifted = &'tcx Goal<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Goal<'tcx>> { +impl<'a, 'tcx> Lift<'tcx> for Goal<'a> { + type Lifted = Goal<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { if tcx.interners.arena.in_arena(*self as *const _) { return Some(unsafe { mem::transmute(*self) }); } @@ -2304,6 +2306,12 @@ impl<'tcx> Borrow for Interned<'tcx, RegionKind> { } } +impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, GoalKind<'tcx>> { + fn borrow<'a>(&'a self) -> &'a GoalKind<'lcx> { + &self.0 + } +} + impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> for Interned<'tcx, List>> { fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] { @@ -2419,7 +2427,8 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { direct_interners!('tcx, region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, - const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx> + const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>, + goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx> ); macro_rules! slice_interners { @@ -2438,7 +2447,7 @@ slice_interners!( type_list: _intern_type_list(Ty), substs: _intern_substs(Kind), clauses: _intern_clauses(Clause), - goals: _intern_goals(Goal) + goal_list: _intern_goals(Goal) ); // This isn't a perfect fit: CanonicalVarInfo slices are always @@ -2818,10 +2827,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { iter.intern_with(|xs| self.intern_goals(xs)) } - pub fn mk_goal(self, goal: Goal<'tcx>) -> &'tcx Goal<'_> { - &self.intern_goals(&[goal])[0] - } - pub fn lint_hir>(self, lint: &'static Lint, hir_id: HirId, diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml index cd21ee601a7d2..16f0f11757a12 100644 --- a/src/librustc_traits/Cargo.toml +++ b/src/librustc_traits/Cargo.toml @@ -16,5 +16,5 @@ rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -chalk-engine = { version = "0.7.0", default-features=false } +chalk-engine = { version = "0.8.0", default-features=false } smallvec = { version = "0.6.5", features = ["union"] } diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index 4c28df97bdf50..dea3aa4372a33 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -19,6 +19,7 @@ use rustc::traits::{ ExClauseFold, ExClauseLift, Goal, + GoalKind, ProgramClause, QuantifierKind }; @@ -92,7 +93,7 @@ impl context::Context for ChalkArenas<'tcx> { type DomainGoal = DomainGoal<'tcx>; - type BindersGoal = ty::Binder<&'tcx Goal<'tcx>>; + type BindersGoal = ty::Binder>; type Parameter = Kind<'tcx>; @@ -102,14 +103,6 @@ impl context::Context for ChalkArenas<'tcx> { type UnificationResult = InferOk<'tcx, ()>; - fn into_goal(domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> { - Goal::DomainGoal(domain_goal) - } - - fn cannot_prove() -> Goal<'tcx> { - Goal::CannotProve - } - fn goal_in_environment( env: &ty::ParamEnv<'tcx>, goal: Goal<'tcx>, @@ -251,15 +244,23 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { impl context::InferenceTable, ChalkArenas<'tcx>> for ChalkInferenceContext<'cx, 'gcx, 'tcx> { + fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> { + self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal)) + } + + fn cannot_prove(&self) -> Goal<'tcx> { + self.infcx.tcx.mk_goal(GoalKind::CannotProve) + } + fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> { - match goal { - Goal::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"), - Goal::And(left, right) => HhGoal::And(*left, *right), - Goal::Not(subgoal) => HhGoal::Not(*subgoal), - Goal::DomainGoal(d) => HhGoal::DomainGoal(d), - Goal::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder), - Goal::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder), - Goal::CannotProve => HhGoal::CannotProve, + match *goal { + GoalKind::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"), + GoalKind::And(left, right) => HhGoal::And(left, right), + GoalKind::Not(subgoal) => HhGoal::Not(subgoal), + GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d), + GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder), + GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder), + GoalKind::CannotProve => HhGoal::CannotProve, } } @@ -363,21 +364,21 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn instantiate_binders_universally( &mut self, - _arg: &ty::Binder<&'tcx Goal<'tcx>>, + _arg: &ty::Binder>, ) -> Goal<'tcx> { panic!("FIXME -- universal instantiation needs sgrif's branch") } fn instantiate_binders_existentially( &mut self, - arg: &ty::Binder<&'tcx Goal<'tcx>>, + arg: &ty::Binder>, ) -> Goal<'tcx> { let (value, _map) = self.infcx.replace_late_bound_regions_with_fresh_var( DUMMY_SP, LateBoundRegionConversionTime::HigherRankedType, arg, ); - *value + value } fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box { diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index ad724babe49fb..4be348fb1703f 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -13,7 +13,14 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::map::definitions::DefPathData; use rustc::hir::{self, ImplPolarity}; use rustc::traits::{ - Clause, Clauses, DomainGoal, FromEnv, Goal, PolyDomainGoal, ProgramClause, WellFormed, + Clause, + Clauses, + DomainGoal, + FromEnv, + GoalKind, + PolyDomainGoal, + ProgramClause, + WellFormed, WhereClause, }; use rustc::ty::query::Providers; @@ -249,7 +256,7 @@ fn program_clauses_for_trait<'a, 'tcx>( let impl_trait: DomainGoal = trait_pred.lower(); // `FromEnv(Self: Trait)` - let from_env_goal = impl_trait.into_from_env_goal().into_goal(); + let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal()); let hypotheses = tcx.intern_goals(&[from_env_goal]); // `Implemented(Self: Trait) :- FromEnv(Self: Trait)` @@ -308,7 +315,7 @@ fn program_clauses_for_trait<'a, 'tcx>( let wf_clause = ProgramClause { goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)), hypotheses: tcx.mk_goals( - wf_conditions.map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause))); @@ -352,7 +359,7 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId hypotheses: tcx.mk_goals( where_clauses .into_iter() - .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))]) @@ -388,7 +395,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( where_clauses .iter() .cloned() - .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; @@ -404,7 +411,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( // ``` // `FromEnv(Ty<...>)` - let from_env_goal = DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal(); + let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal()); let hypotheses = tcx.intern_goals(&[from_env_goal]); // For each where clause `WC`: @@ -482,7 +489,7 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( hypotheses: tcx.mk_goals( hypotheses .into_iter() - .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))]) From 96ff8273951269565fb047aa00e42ab3b8038968 Mon Sep 17 00:00:00 2001 From: scalexm Date: Mon, 8 Oct 2018 12:54:56 +0200 Subject: [PATCH 11/18] Add chalk rules related to associated type defs * Rule ProjectionEq-Skolemize * Rule WellFormed-AssocTy * Rule Implied-Trait-From-AssocTy --- src/librustc_traits/lowering.rs | 93 ++++++++++++++++++++++--- src/test/ui/chalkify/lower_trait.rs | 9 +-- src/test/ui/chalkify/lower_trait.stderr | 23 ++++-- 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 4be348fb1703f..181106d3f84bf 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -362,7 +362,7 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; - tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))]) + tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))) } pub fn program_clauses_for_type_def<'a, 'tcx>( @@ -430,10 +430,86 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( } pub fn program_clauses_for_associated_type_def<'a, 'tcx>( - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _item_id: DefId, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_id: DefId, ) -> Clauses<'tcx> { - unimplemented!() + // Rule ProjectionEq-Skolemize + // + // ``` + // trait Trait { + // type AssocType; + // } + // ``` + // + // `ProjectionEq` can succeed by skolemizing, see "associated type" + // chapter for more: + // ``` + // forall { + // ProjectionEq( + // >::AssocType = + // (Trait::AssocType) + // ) + // } + // ``` + + let item = tcx.associated_item(item_id); + debug_assert_eq!(item.kind, ty::AssociatedKind::Type); + let trait_id = match item.container { + ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id, + _ => bug!("not an trait container"), + }; + let trait_ref = ty::TraitRef::identity(tcx, trait_id); + + let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident); + let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty)); + let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate { + projection_ty, + ty: placeholder_ty, + }); + + let projection_eq_clause = ProgramClause { + goal: DomainGoal::Holds(projection_eq), + hypotheses: &ty::List::empty(), + }; + + // Rule WellFormed-AssocTy + // ``` + // forall { + // WellFormed((Trait::AssocType)) + // :- Implemented(Self: Trait) + // } + // ``` + + let trait_predicate = ty::TraitPredicate { trait_ref }; + let hypothesis = tcx.mk_goal( + DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal() + ); + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)), + hypotheses: tcx.mk_goals(iter::once(hypothesis)), + }; + + // Rule Implied-Trait-From-AssocTy + // ``` + // forall { + // FromEnv(Self: Trait) + // :- FromEnv((Trait::AssocType)) + // } + // ``` + + let hypothesis = tcx.mk_goal( + DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal() + ); + let from_env_clause = ProgramClause { + goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)), + hypotheses: tcx.mk_goals(iter::once(hypothesis)), + }; + + let clauses = iter::once(projection_eq_clause) + .chain(iter::once(wf_clause)) + .chain(iter::once(from_env_clause)); + let clauses = clauses.map(|clause| Clause::ForAll(ty::Binder::dummy(clause))); + tcx.mk_clauses(clauses) } pub fn program_clauses_for_associated_type_value<'a, 'tcx>( @@ -442,10 +518,11 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( ) -> Clauses<'tcx> { // Rule Normalize-From-Impl (see rustc guide) // - // ```impl Trait for A0 - // { + // ``` + // impl Trait for A0 { // type AssocType = T; - // }``` + // } + // ``` // // FIXME: For the moment, we don't account for where clauses written on the associated // ty definition (i.e. in the trait def, as in `type AssocType where T: Sized`). @@ -492,7 +569,7 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; - tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))]) + tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))) } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs index c5ba5beeca7a5..ba7d4ff0d9bf5 100644 --- a/src/test/ui/chalkify/lower_trait.rs +++ b/src/test/ui/chalkify/lower_trait.rs @@ -10,11 +10,12 @@ #![feature(rustc_attrs)] +trait Bar { } + #[rustc_dump_program_clauses] //~ ERROR program clause dump -trait Foo { - fn s(_: S) -> S; - fn t(_: T) -> T; - fn u(_: U) -> U; +trait Foo { + #[rustc_dump_program_clauses] //~ ERROR program clause dump + type Assoc: Bar + ?Sized; } fn main() { diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr index c4e768415d60b..dc2375277e734 100644 --- a/src/test/ui/chalkify/lower_trait.stderr +++ b/src/test/ui/chalkify/lower_trait.stderr @@ -1,14 +1,23 @@ error: program clause dump - --> $DIR/lower_trait.rs:13:1 + --> $DIR/lower_trait.rs:15:1 | LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo). - = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo). - = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo). - = note: Implemented(Self: Foo) :- FromEnv(Self: Foo). - = note: WellFormed(Self: Foo) :- Implemented(Self: Foo), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(U: std::marker::Sized). + = note: FromEnv(>::Assoc: Bar) :- FromEnv(Self: Foo). + = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo). + = note: Implemented(Self: Foo) :- FromEnv(Self: Foo). + = note: WellFormed(Self: Foo) :- Implemented(Self: Foo), WellFormed(S: std::marker::Sized), WellFormed(>::Assoc: Bar). -error: aborting due to previous error +error: program clause dump + --> $DIR/lower_trait.rs:17:5 + | +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: FromEnv(Self: Foo) :- FromEnv(Unnormalized(>::Assoc)). + = note: ProjectionEq(>::Assoc == Unnormalized(>::Assoc)). + = note: WellFormed(Unnormalized(>::Assoc)) :- Implemented(Self: Foo). + +error: aborting due to 2 previous errors From 282559cff607c19eb0a74e1ddf90df781cd77849 Mon Sep 17 00:00:00 2001 From: scalexm Date: Mon, 8 Oct 2018 15:20:16 +0200 Subject: [PATCH 12/18] Compute flags for `ty::UnnormalizedProjection` --- src/librustc/ty/flags.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index c3d41873009a7..10a90dfc8a8cf 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -148,7 +148,10 @@ impl FlagComputation { self.add_projection_ty(data); } - &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + &ty::UnnormalizedProjection(ref data) => { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_projection_ty(data); + }, &ty::Opaque(_, substs) => { self.add_flags(TypeFlags::HAS_PROJECTION); From dc2343c1a8d89cda5012bac175cca9901dd09db9 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 2 Oct 2018 10:37:56 +0200 Subject: [PATCH 13/18] Update feature-gate listing --- src/libsyntax/feature_gate.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 24ee24640558e..4ddbaee5aa443 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -433,9 +433,6 @@ declare_features! ( // #[doc(alias = "...")] (active, doc_alias, "1.27.0", Some(50146), None), - // Scoped lints - (active, tool_lints, "1.28.0", Some(44690), None), - // Allows irrefutable patterns in if-let and while-let statements (RFC 2086) (active, irrefutable_let_patterns, "1.27.0", Some(44495), None), @@ -679,6 +676,8 @@ declare_features! ( (accepted, pattern_parentheses, "1.31.0", Some(51087), None), // Allows the definition of `const fn` functions. (accepted, min_const_fn, "1.31.0", Some(53555), None), + // Scoped lints + (accepted, tool_lints, "1.31.0", Some(44690), None), ); // If you change this, please modify src/doc/unstable-book as well. You must From 5e9084ccc3e3e1265bd52481f6586a5cbaaafc5a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 2 Oct 2018 10:44:49 +0200 Subject: [PATCH 14/18] Remove `feature(tool_lints)` from tests --- src/test/run-pass/tool_lints.rs | 2 +- src/test/run-pass/tool_lints_2018_preview.rs | 2 +- src/test/ui-fulldeps/lint_tool_test.rs | 2 +- src/test/ui/tool_lints-fail.rs | 2 +- src/test/ui/tool_lints.rs | 2 +- src/test/ui/unknown-lint-tool-name.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/run-pass/tool_lints.rs b/src/test/run-pass/tool_lints.rs index 24ec43b12f60e..2705c03598a0d 100644 --- a/src/test/run-pass/tool_lints.rs +++ b/src/test/run-pass/tool_lints.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #![deny(unknown_lints)] #[allow(clippy::almost_swapped)] diff --git a/src/test/run-pass/tool_lints_2018_preview.rs b/src/test/run-pass/tool_lints_2018_preview.rs index 6cd57eaa19595..57df3e072a8dc 100644 --- a/src/test/run-pass/tool_lints_2018_preview.rs +++ b/src/test/run-pass/tool_lints_2018_preview.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #![feature(rust_2018_preview)] #![deny(unknown_lints)] diff --git a/src/test/ui-fulldeps/lint_tool_test.rs b/src/test/ui-fulldeps/lint_tool_test.rs index ebe10b3714f20..11b70d1d7809c 100644 --- a/src/test/ui-fulldeps/lint_tool_test.rs +++ b/src/test/ui-fulldeps/lint_tool_test.rs @@ -11,8 +11,8 @@ // aux-build:lint_tool_test.rs // ignore-stage1 // compile-flags: --cfg foo + #![feature(plugin)] -#![feature(tool_lints)] #![plugin(lint_tool_test)] #![allow(dead_code)] #![cfg_attr(foo, warn(test_lint))] diff --git a/src/test/ui/tool_lints-fail.rs b/src/test/ui/tool_lints-fail.rs index ea1efab4cb6f8..4134fca1ce6ca 100644 --- a/src/test/ui/tool_lints-fail.rs +++ b/src/test/ui/tool_lints-fail.rs @@ -10,7 +10,7 @@ // Don't allow tool_lints, which aren't scoped -#![feature(tool_lints)] + #![deny(unknown_lints)] #![deny(clippy)] //~ ERROR: unknown lint: `clippy` diff --git a/src/test/ui/tool_lints.rs b/src/test/ui/tool_lints.rs index 71f90b17c18fc..001f2f11e5cb3 100644 --- a/src/test/ui/tool_lints.rs +++ b/src/test/ui/tool_lints.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #[warn(foo::bar)] //~^ ERROR an unknown tool name found in scoped lint: `foo::bar` diff --git a/src/test/ui/unknown-lint-tool-name.rs b/src/test/ui/unknown-lint-tool-name.rs index 78b736edcebe6..a1d6c27e518e5 100644 --- a/src/test/ui/unknown-lint-tool-name.rs +++ b/src/test/ui/unknown-lint-tool-name.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar` From a249981a4390130e45fc2d6b30e4f2f8b1c49803 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 2 Oct 2018 10:51:12 +0200 Subject: [PATCH 15/18] Remove feature-gate tests --- .../feature-gates/feature-gate-tool_lints-fail.rs | 12 ------------ .../feature-gate-tool_lints-fail.stderr | 11 ----------- .../ui/feature-gates/feature-gate-tool_lints.rs | 15 --------------- .../feature-gates/feature-gate-tool_lints.stderr | 11 ----------- 4 files changed, 49 deletions(-) delete mode 100644 src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-tool_lints.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-tool_lints.stderr diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs b/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs deleted file mode 100644 index c311eb7ed7ae1..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr b/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr deleted file mode 100644 index 33ee79cd2011a..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: scoped lint `clippy::assign_ops` is experimental (see issue #44690) - --> $DIR/feature-gate-tool_lints-fail.rs:11:8 - | -LL | #[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(tool_lints)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints.rs b/src/test/ui/feature-gates/feature-gate-tool_lints.rs deleted file mode 100644 index 3ef67982be9a4..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-tool_lints.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[warn(clippy::decimal_literal_representation)] -//~^ ERROR scoped lint `clippy::decimal_literal_representation` is experimental -fn main() { - let a = 65_535; -} diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints.stderr b/src/test/ui/feature-gates/feature-gate-tool_lints.stderr deleted file mode 100644 index 8019b1e6a28f6..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-tool_lints.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: scoped lint `clippy::decimal_literal_representation` is experimental (see issue #44690) - --> $DIR/feature-gate-tool_lints.rs:11:8 - | -LL | #[warn(clippy::decimal_literal_representation)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(tool_lints)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. From ac231d40a33f9b4ef0fb50b22a0a4686dc42ecfc Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 2 Oct 2018 10:59:41 +0200 Subject: [PATCH 16/18] Remove feature-gate code --- src/librustc/lint/levels.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 87d33e473e7f6..bcba5c97e3317 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -22,7 +22,6 @@ use session::{config::nightly_options, Session}; use syntax::ast; use syntax::attr; use syntax::source_map::MultiSpan; -use syntax::feature_gate; use syntax::symbol::Symbol; use util::nodemap::FxHashMap; @@ -228,18 +227,7 @@ impl<'a> LintLevelsBuilder<'a> { } }; let tool_name = if let Some(lint_tool) = word.is_scoped() { - let gate_feature = !self.sess.features_untracked().tool_lints; - let known_tool = attr::is_known_lint_tool(lint_tool); - if gate_feature { - feature_gate::emit_feature_err( - &sess.parse_sess, - "tool_lints", - word.span, - feature_gate::GateIssue::Language, - &format!("scoped lint `{}` is experimental", word.ident), - ); - } - if !known_tool { + if !attr::is_known_lint_tool(lint_tool) { span_err!( sess, lint_tool.span, @@ -247,9 +235,6 @@ impl<'a> LintLevelsBuilder<'a> { "an unknown tool name found in scoped lint: `{}`", word.ident ); - } - - if gate_feature || !known_tool { continue; } From 6328850e6d6717f2d137274598b7c92602a01edb Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 2 Oct 2018 11:19:38 +0200 Subject: [PATCH 17/18] Remove unstable-book documentation --- .../src/language-features/tool-lints.md | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/tool-lints.md diff --git a/src/doc/unstable-book/src/language-features/tool-lints.md b/src/doc/unstable-book/src/language-features/tool-lints.md deleted file mode 100644 index 5c0d33b5ab0c4..0000000000000 --- a/src/doc/unstable-book/src/language-features/tool-lints.md +++ /dev/null @@ -1,35 +0,0 @@ -# `tool_lints` - -The tracking issue for this feature is: [#44690] - -[#44690]: https://github.com/rust-lang/rust/issues/44690 - ------------------------- - -Tool lints let you use scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of -certain tools. - -Currently `clippy` is the only available lint tool. - -It is recommended for lint tools to implement the scoped lints like this: - -- `#[_(TOOL_NAME::lintname)]`: for lint names -- `#[_(TOOL_NAME::lintgroup)]`: for groups of lints -- `#[_(TOOL_NAME::all)]`: for (almost[^1]) all lints - -## An example - -```rust -#![feature(tool_lints)] - -#![warn(clippy::pedantic)] - -#[allow(clippy::filter_map)] -fn main() { - let v = vec![0; 10]; - let _ = v.into_iter().filter(|&x| x < 1).map(|x| x + 1).collect::>(); - println!("No filter_map()!"); -} -``` - -[^1]: Some defined lint groups can be excluded here. From ffe15277ff182b1981b2d46264882bca31b89d13 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 2 Oct 2018 18:15:13 +0200 Subject: [PATCH 18/18] Remove nightly check for tool_lints warning --- src/librustc/lint/levels.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index bcba5c97e3317..950754a07ab09 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -18,7 +18,7 @@ use lint::context::CheckLintNameResult; use lint::{self, Lint, LintId, Level, LintSource}; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; -use session::{config::nightly_options, Session}; +use session::Session; use syntax::ast; use syntax::attr; use syntax::source_map::MultiSpan; @@ -284,13 +284,7 @@ impl<'a> LintLevelsBuilder<'a> { "change it to", new_lint_name.to_string(), Applicability::MachineApplicable, - ); - - if nightly_options::is_nightly_build() { - err.emit(); - } else { - err.cancel(); - } + ).emit(); let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span); for id in ids {