From f63b88c761f935d9b2c220a1b4e3abf0c0681c69 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 15 Feb 2020 19:04:20 -0500 Subject: [PATCH 01/32] Permit attributes on 'if' expressions Previously, attributes on 'if' expressions (e.g. #[attr] if true {}) were disallowed during parsing. This made it impossible for macros to perform any custom handling of such attributes (e.g. stripping them away), since a compilation error would be emitted before they ever had a chance to run. This PR permits attributes on 'if' expressions ('if-attrs' from here on). Both built-in attributes (e.g. `#[allow]`, `#[cfg]`) are supported. We still do *not* accept attributes on 'other parts' of an if-else chain. That is, the following code snippet still fails to parse: ```rust if true {} #[attr] else if false {} else #[attr] if false {} #[attr] else {} ``` --- src/librustc_parse/parser/expr.rs | 9 ------ src/test/pretty/if-attr.rs | 28 +++++++++++++++++ src/test/ui/parser/attr-stmt-expr-attr-bad.rs | 10 ++---- .../ui/parser/if-attrs/cfg-false-if-attr.rs | 31 +++++++++++++++++++ src/test/ui/parser/if-attrs/else-attrs.rs | 25 +++++++++++++++ src/test/ui/parser/if-attrs/else-attrs.stderr | 27 ++++++++++++++++ .../ui/parser/if-attrs/let-chains-attr.rs | 13 ++++++++ .../ui/parser/if-attrs/let-chains-attr.stderr | 8 +++++ src/test/ui/parser/recovery-attr-on-if.rs | 2 -- src/test/ui/parser/recovery-attr-on-if.stderr | 18 ++--------- 10 files changed, 137 insertions(+), 34 deletions(-) create mode 100644 src/test/pretty/if-attr.rs create mode 100644 src/test/ui/parser/if-attrs/cfg-false-if-attr.rs create mode 100644 src/test/ui/parser/if-attrs/else-attrs.rs create mode 100644 src/test/ui/parser/if-attrs/else-attrs.stderr create mode 100644 src/test/ui/parser/if-attrs/let-chains-attr.rs create mode 100644 src/test/ui/parser/if-attrs/let-chains-attr.stderr diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 18ddd23588e48..f31686afd1a0b 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -665,20 +665,11 @@ impl<'a> Parser<'a> { expr.map(|mut expr| { attrs.extend::>(expr.attrs.into()); expr.attrs = attrs; - self.error_attr_on_if_expr(&expr); expr }) }) } - fn error_attr_on_if_expr(&self, expr: &Expr) { - if let (ExprKind::If(..), [a0, ..]) = (&expr.kind, &*expr.attrs) { - // Just point to the first attribute in there... - self.struct_span_err(a0.span, "attributes are not yet allowed on `if` expressions") - .emit(); - } - } - fn parse_dot_or_call_expr_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { loop { if self.eat(&token::Question) { diff --git a/src/test/pretty/if-attr.rs b/src/test/pretty/if-attr.rs new file mode 100644 index 0000000000000..463476737a92f --- /dev/null +++ b/src/test/pretty/if-attr.rs @@ -0,0 +1,28 @@ +// pp-exact + +#[cfg(FALSE)] +fn simple_attr() { + + #[attr] + if true { } + + #[allow_warnings] + if true { } +} + +#[cfg(FALSE)] +fn if_else_chain() { + + #[first_attr] + if true { } else if false { } else { } +} + +#[cfg(FALSE)] +fn if_let() { + + #[attr] + if let Some(_) = Some(true) { } +} + + +fn main() { } diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.rs b/src/test/ui/parser/attr-stmt-expr-attr-bad.rs index 118bff8144c7f..f3980a596481c 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.rs +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.rs @@ -38,8 +38,6 @@ fn main() {} //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } //~^ ERROR expected `{`, found `#` #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } @@ -51,14 +49,11 @@ fn main() {} #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions -//~| ERROR expected `{`, found `#` +//~^ ERROR expected `{`, found `#` #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } //~^ ERROR expected `{`, found `#` #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } //~^ ERROR expected `{`, found `#` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } @@ -70,8 +65,7 @@ fn main() {} #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions -//~| ERROR expected `{`, found `#` +//~^ ERROR expected `{`, found `#` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } //~^ ERROR expected `{`, found `#` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } diff --git a/src/test/ui/parser/if-attrs/cfg-false-if-attr.rs b/src/test/ui/parser/if-attrs/cfg-false-if-attr.rs new file mode 100644 index 0000000000000..2932ec1a23195 --- /dev/null +++ b/src/test/ui/parser/if-attrs/cfg-false-if-attr.rs @@ -0,0 +1,31 @@ +// check-pass + +#[cfg(FALSE)] +fn simple_attr() { + #[attr] if true {} + #[allow_warnings] if true {} +} + +#[cfg(FALSE)] +fn if_else_chain() { + #[first_attr] if true { + } else if false { + } else { + } +} + +#[cfg(FALSE)] +fn if_let() { + #[attr] if let Some(_) = Some(true) {} +} + +macro_rules! custom_macro { + ($expr:expr) => {} +} + +custom_macro! { + #[attr] if true {} +} + + +fn main() {} diff --git a/src/test/ui/parser/if-attrs/else-attrs.rs b/src/test/ui/parser/if-attrs/else-attrs.rs new file mode 100644 index 0000000000000..4394b2100c1b5 --- /dev/null +++ b/src/test/ui/parser/if-attrs/else-attrs.rs @@ -0,0 +1,25 @@ +#[cfg(FALSE)] +fn if_else_parse_error() { + if true { + } #[attr] else if false { //~ ERROR expected + } +} + +#[cfg(FALSE)] +fn else_attr_ifparse_error() { + if true { + } else #[attr] if false { //~ ERROR expected + } else { + } +} + +#[cfg(FALSE)] +fn else_parse_error() { + if true { + } else if false { + } #[attr] else { //~ ERROR expected + } +} + +fn main() { +} diff --git a/src/test/ui/parser/if-attrs/else-attrs.stderr b/src/test/ui/parser/if-attrs/else-attrs.stderr new file mode 100644 index 0000000000000..af25b6abc0a3a --- /dev/null +++ b/src/test/ui/parser/if-attrs/else-attrs.stderr @@ -0,0 +1,27 @@ +error: expected expression, found keyword `else` + --> $DIR/else-attrs.rs:4:15 + | +LL | } #[attr] else if false { + | ^^^^ expected expression + +error: expected `{`, found `#` + --> $DIR/else-attrs.rs:11:12 + | +LL | } else #[attr] if false { + | ^ expected `{` + | +help: try placing this code inside a block + | +LL | } else #[attr] { if false { +LL | } else { +LL | } } + | + +error: expected expression, found keyword `else` + --> $DIR/else-attrs.rs:20:15 + | +LL | } #[attr] else { + | ^^^^ expected expression + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/if-attrs/let-chains-attr.rs b/src/test/ui/parser/if-attrs/let-chains-attr.rs new file mode 100644 index 0000000000000..5237a9ff3961a --- /dev/null +++ b/src/test/ui/parser/if-attrs/let-chains-attr.rs @@ -0,0 +1,13 @@ +// check-pass + +#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete + +#[cfg(FALSE)] +fn foo() { + #[attr] + if let Some(_) = Some(true) && let Ok(_) = Ok(1) { + } else if let Some(false) = Some(true) { + } +} + +fn main() {} diff --git a/src/test/ui/parser/if-attrs/let-chains-attr.stderr b/src/test/ui/parser/if-attrs/let-chains-attr.stderr new file mode 100644 index 0000000000000..a6c91bb9203b3 --- /dev/null +++ b/src/test/ui/parser/if-attrs/let-chains-attr.stderr @@ -0,0 +1,8 @@ +warning: the feature `let_chains` is incomplete and may cause the compiler to crash + --> $DIR/let-chains-attr.rs:3:12 + | +LL | #![feature(let_chains)] + | ^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/parser/recovery-attr-on-if.rs b/src/test/ui/parser/recovery-attr-on-if.rs index 0d1f5be7b4930..b4fb25ec8d344 100644 --- a/src/test/ui/parser/recovery-attr-on-if.rs +++ b/src/test/ui/parser/recovery-attr-on-if.rs @@ -1,9 +1,7 @@ fn main() { #[attr] if true {}; //~^ ERROR cannot find attribute - //~| ERROR attributes are not yet allowed on `if` expressions #[attr] if true {}; //~^ ERROR cannot find attribute - //~| ERROR attributes are not yet allowed on `if` expressions let _recovery_witness: () = 0; //~ ERROR mismatched types } diff --git a/src/test/ui/parser/recovery-attr-on-if.stderr b/src/test/ui/parser/recovery-attr-on-if.stderr index a02846827c9ab..cbf2714a1a1de 100644 --- a/src/test/ui/parser/recovery-attr-on-if.stderr +++ b/src/test/ui/parser/recovery-attr-on-if.stderr @@ -1,17 +1,5 @@ -error: attributes are not yet allowed on `if` expressions - --> $DIR/recovery-attr-on-if.rs:2:5 - | -LL | #[attr] if true {}; - | ^^^^^^^ - -error: attributes are not yet allowed on `if` expressions - --> $DIR/recovery-attr-on-if.rs:5:5 - | -LL | #[attr] if true {}; - | ^^^^^^^ - error: cannot find attribute `attr` in this scope - --> $DIR/recovery-attr-on-if.rs:5:7 + --> $DIR/recovery-attr-on-if.rs:4:7 | LL | #[attr] if true {}; | ^^^^ @@ -23,13 +11,13 @@ LL | #[attr] if true {}; | ^^^^ error[E0308]: mismatched types - --> $DIR/recovery-attr-on-if.rs:8:33 + --> $DIR/recovery-attr-on-if.rs:6:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. From e912d9d7ecd9d326affd18f7b133dafb72ee8896 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 15 Feb 2020 19:13:36 -0500 Subject: [PATCH 02/32] Test #[allow(unused)] on `if` expression --- src/test/ui/parser/if-attrs/builtin-if-attr.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/ui/parser/if-attrs/builtin-if-attr.rs diff --git a/src/test/ui/parser/if-attrs/builtin-if-attr.rs b/src/test/ui/parser/if-attrs/builtin-if-attr.rs new file mode 100644 index 0000000000000..7e290661501c9 --- /dev/null +++ b/src/test/ui/parser/if-attrs/builtin-if-attr.rs @@ -0,0 +1,12 @@ +// check-pass + +fn main() { + #[allow(unused_variables)] + if true { + let a = 1; + } else if false { + let b = 1; + } else { + let c = 1; + } +} From e9ec47bb70810f972e6565d496120b0b00f261f0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 10:45:21 -0500 Subject: [PATCH 03/32] Test that stmt_expr_attrs properly gates if-attrs --- src/test/ui/parser/if-attrs/stmt-expr-gated.rs | 6 ++++++ src/test/ui/parser/if-attrs/stmt-expr-gated.stderr | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/ui/parser/if-attrs/stmt-expr-gated.rs create mode 100644 src/test/ui/parser/if-attrs/stmt-expr-gated.stderr diff --git a/src/test/ui/parser/if-attrs/stmt-expr-gated.rs b/src/test/ui/parser/if-attrs/stmt-expr-gated.rs new file mode 100644 index 0000000000000..38599c8e67c4e --- /dev/null +++ b/src/test/ui/parser/if-attrs/stmt-expr-gated.rs @@ -0,0 +1,6 @@ +fn main() { + let _ = #[deny(warnings)] if true { //~ ERROR attributes on expressions + } else if false { + } else { + }; +} diff --git a/src/test/ui/parser/if-attrs/stmt-expr-gated.stderr b/src/test/ui/parser/if-attrs/stmt-expr-gated.stderr new file mode 100644 index 0000000000000..47dac39a9ae88 --- /dev/null +++ b/src/test/ui/parser/if-attrs/stmt-expr-gated.stderr @@ -0,0 +1,12 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt-expr-gated.rs:2:13 + | +LL | let _ = #[deny(warnings)] if true { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 9a299e4e210ff91ec59bf9f09bdb402196e02bd5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 10:47:27 -0500 Subject: [PATCH 04/32] Test trying to cfg-remove an `if` expression --- src/test/ui/parser/if-attrs/bad-cfg.rs | 5 +++++ src/test/ui/parser/if-attrs/bad-cfg.stderr | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/ui/parser/if-attrs/bad-cfg.rs create mode 100644 src/test/ui/parser/if-attrs/bad-cfg.stderr diff --git a/src/test/ui/parser/if-attrs/bad-cfg.rs b/src/test/ui/parser/if-attrs/bad-cfg.rs new file mode 100644 index 0000000000000..3f84929a00e4f --- /dev/null +++ b/src/test/ui/parser/if-attrs/bad-cfg.rs @@ -0,0 +1,5 @@ +#![feature(stmt_expr_attributes)] + +fn main() { + let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression +} diff --git a/src/test/ui/parser/if-attrs/bad-cfg.stderr b/src/test/ui/parser/if-attrs/bad-cfg.stderr new file mode 100644 index 0000000000000..8a2890886a15c --- /dev/null +++ b/src/test/ui/parser/if-attrs/bad-cfg.stderr @@ -0,0 +1,8 @@ +error: removing an expression is not supported in this position + --> $DIR/bad-cfg.rs:4:13 + | +LL | let _ = #[cfg(FALSE)] if true {}; + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + From b00f6745c4df0e979dd53dcbf43ededf5728e349 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 10:48:13 -0500 Subject: [PATCH 05/32] Remove recovery test --- src/test/ui/parser/recovery-attr-on-if.rs | 7 ------ src/test/ui/parser/recovery-attr-on-if.stderr | 23 ------------------- 2 files changed, 30 deletions(-) delete mode 100644 src/test/ui/parser/recovery-attr-on-if.rs delete mode 100644 src/test/ui/parser/recovery-attr-on-if.stderr diff --git a/src/test/ui/parser/recovery-attr-on-if.rs b/src/test/ui/parser/recovery-attr-on-if.rs deleted file mode 100644 index b4fb25ec8d344..0000000000000 --- a/src/test/ui/parser/recovery-attr-on-if.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - #[attr] if true {}; - //~^ ERROR cannot find attribute - #[attr] if true {}; - //~^ ERROR cannot find attribute - let _recovery_witness: () = 0; //~ ERROR mismatched types -} diff --git a/src/test/ui/parser/recovery-attr-on-if.stderr b/src/test/ui/parser/recovery-attr-on-if.stderr deleted file mode 100644 index cbf2714a1a1de..0000000000000 --- a/src/test/ui/parser/recovery-attr-on-if.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: cannot find attribute `attr` in this scope - --> $DIR/recovery-attr-on-if.rs:4:7 - | -LL | #[attr] if true {}; - | ^^^^ - -error: cannot find attribute `attr` in this scope - --> $DIR/recovery-attr-on-if.rs:2:7 - | -LL | #[attr] if true {}; - | ^^^^ - -error[E0308]: mismatched types - --> $DIR/recovery-attr-on-if.rs:6:33 - | -LL | let _recovery_witness: () = 0; - | -- ^ expected `()`, found integer - | | - | expected due to this - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0308`. From e11cdfdae48f8793c618834227114bcb5a6d57bd Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 10:49:34 -0500 Subject: [PATCH 06/32] Add run-pass test suggested by @joshtriplett --- src/test/ui/parser/if-attrs/gate-whole-expr.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/ui/parser/if-attrs/gate-whole-expr.rs diff --git a/src/test/ui/parser/if-attrs/gate-whole-expr.rs b/src/test/ui/parser/if-attrs/gate-whole-expr.rs new file mode 100644 index 0000000000000..efce28e1d5bb2 --- /dev/null +++ b/src/test/ui/parser/if-attrs/gate-whole-expr.rs @@ -0,0 +1,15 @@ +// run-pass + +fn main() { + let x = 1; + + #[cfg(FALSE)] + if false { + x = 2; + } else if true { + x = 3; + } else { + x = 4; + } + assert_eq!(x, 1); +} From 7f19358c9ef51a130e0177d327eaac5adc6d73ad Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 10:50:03 -0500 Subject: [PATCH 07/32] Move if-attr tests to their own directory --- src/test/ui/{parser => }/if-attrs/bad-cfg.rs | 0 src/test/ui/{parser => }/if-attrs/bad-cfg.stderr | 0 src/test/ui/{parser => }/if-attrs/builtin-if-attr.rs | 0 src/test/ui/{parser => }/if-attrs/cfg-false-if-attr.rs | 0 src/test/ui/{parser => }/if-attrs/else-attrs.rs | 0 src/test/ui/{parser => }/if-attrs/else-attrs.stderr | 0 src/test/ui/{parser => }/if-attrs/gate-whole-expr.rs | 0 src/test/ui/{parser => }/if-attrs/let-chains-attr.rs | 0 src/test/ui/{parser => }/if-attrs/let-chains-attr.stderr | 0 src/test/ui/{parser => }/if-attrs/stmt-expr-gated.rs | 0 src/test/ui/{parser => }/if-attrs/stmt-expr-gated.stderr | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{parser => }/if-attrs/bad-cfg.rs (100%) rename src/test/ui/{parser => }/if-attrs/bad-cfg.stderr (100%) rename src/test/ui/{parser => }/if-attrs/builtin-if-attr.rs (100%) rename src/test/ui/{parser => }/if-attrs/cfg-false-if-attr.rs (100%) rename src/test/ui/{parser => }/if-attrs/else-attrs.rs (100%) rename src/test/ui/{parser => }/if-attrs/else-attrs.stderr (100%) rename src/test/ui/{parser => }/if-attrs/gate-whole-expr.rs (100%) rename src/test/ui/{parser => }/if-attrs/let-chains-attr.rs (100%) rename src/test/ui/{parser => }/if-attrs/let-chains-attr.stderr (100%) rename src/test/ui/{parser => }/if-attrs/stmt-expr-gated.rs (100%) rename src/test/ui/{parser => }/if-attrs/stmt-expr-gated.stderr (100%) diff --git a/src/test/ui/parser/if-attrs/bad-cfg.rs b/src/test/ui/if-attrs/bad-cfg.rs similarity index 100% rename from src/test/ui/parser/if-attrs/bad-cfg.rs rename to src/test/ui/if-attrs/bad-cfg.rs diff --git a/src/test/ui/parser/if-attrs/bad-cfg.stderr b/src/test/ui/if-attrs/bad-cfg.stderr similarity index 100% rename from src/test/ui/parser/if-attrs/bad-cfg.stderr rename to src/test/ui/if-attrs/bad-cfg.stderr diff --git a/src/test/ui/parser/if-attrs/builtin-if-attr.rs b/src/test/ui/if-attrs/builtin-if-attr.rs similarity index 100% rename from src/test/ui/parser/if-attrs/builtin-if-attr.rs rename to src/test/ui/if-attrs/builtin-if-attr.rs diff --git a/src/test/ui/parser/if-attrs/cfg-false-if-attr.rs b/src/test/ui/if-attrs/cfg-false-if-attr.rs similarity index 100% rename from src/test/ui/parser/if-attrs/cfg-false-if-attr.rs rename to src/test/ui/if-attrs/cfg-false-if-attr.rs diff --git a/src/test/ui/parser/if-attrs/else-attrs.rs b/src/test/ui/if-attrs/else-attrs.rs similarity index 100% rename from src/test/ui/parser/if-attrs/else-attrs.rs rename to src/test/ui/if-attrs/else-attrs.rs diff --git a/src/test/ui/parser/if-attrs/else-attrs.stderr b/src/test/ui/if-attrs/else-attrs.stderr similarity index 100% rename from src/test/ui/parser/if-attrs/else-attrs.stderr rename to src/test/ui/if-attrs/else-attrs.stderr diff --git a/src/test/ui/parser/if-attrs/gate-whole-expr.rs b/src/test/ui/if-attrs/gate-whole-expr.rs similarity index 100% rename from src/test/ui/parser/if-attrs/gate-whole-expr.rs rename to src/test/ui/if-attrs/gate-whole-expr.rs diff --git a/src/test/ui/parser/if-attrs/let-chains-attr.rs b/src/test/ui/if-attrs/let-chains-attr.rs similarity index 100% rename from src/test/ui/parser/if-attrs/let-chains-attr.rs rename to src/test/ui/if-attrs/let-chains-attr.rs diff --git a/src/test/ui/parser/if-attrs/let-chains-attr.stderr b/src/test/ui/if-attrs/let-chains-attr.stderr similarity index 100% rename from src/test/ui/parser/if-attrs/let-chains-attr.stderr rename to src/test/ui/if-attrs/let-chains-attr.stderr diff --git a/src/test/ui/parser/if-attrs/stmt-expr-gated.rs b/src/test/ui/if-attrs/stmt-expr-gated.rs similarity index 100% rename from src/test/ui/parser/if-attrs/stmt-expr-gated.rs rename to src/test/ui/if-attrs/stmt-expr-gated.rs diff --git a/src/test/ui/parser/if-attrs/stmt-expr-gated.stderr b/src/test/ui/if-attrs/stmt-expr-gated.stderr similarity index 100% rename from src/test/ui/parser/if-attrs/stmt-expr-gated.stderr rename to src/test/ui/if-attrs/stmt-expr-gated.stderr From 1b681d6652bacce6b741ca66725f25b9afb16bc8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 11:01:51 -0500 Subject: [PATCH 08/32] Test that cfg-gated if-exprs are not type-checked --- src/test/ui/if-attrs/cfg-false-if-attr.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/ui/if-attrs/cfg-false-if-attr.rs b/src/test/ui/if-attrs/cfg-false-if-attr.rs index 2932ec1a23195..1f77a1bb3427d 100644 --- a/src/test/ui/if-attrs/cfg-false-if-attr.rs +++ b/src/test/ui/if-attrs/cfg-false-if-attr.rs @@ -19,6 +19,18 @@ fn if_let() { #[attr] if let Some(_) = Some(true) {} } +fn bar() { + #[cfg(FALSE)] + if true { + let x: () = true; // Should not error due to the #[cfg(FALSE)] + } + + #[cfg_attr(not(unset_attr), cfg(FALSE))] + if true { + let a: () = true; // Should not error due to the applied #[cfg(FALSE)] + } +} + macro_rules! custom_macro { ($expr:expr) => {} } From 37c2c38aeb0d50f7b956200c698bc59fce6e7181 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 11:05:31 -0500 Subject: [PATCH 09/32] Extent pretty-print test --- src/test/pretty/if-attr.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/pretty/if-attr.rs b/src/test/pretty/if-attr.rs index 463476737a92f..652604fc7f34b 100644 --- a/src/test/pretty/if-attr.rs +++ b/src/test/pretty/if-attr.rs @@ -24,5 +24,14 @@ fn if_let() { if let Some(_) = Some(true) { } } +#[cfg(FALSE)] +fn let_attr_if() { + let _ = #[attr] if let _ = 0 { }; + let _ = #[attr] if true { }; + + let _ = #[attr] if let _ = 0 { } else { }; + let _ = #[attr] if true { } else { }; +} + fn main() { } From 66b152cf9fd53b27027c66378a73404b92c6e35b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Feb 2020 11:36:04 -0500 Subject: [PATCH 10/32] Fix tabs --- src/test/ui/if-attrs/gate-whole-expr.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/ui/if-attrs/gate-whole-expr.rs b/src/test/ui/if-attrs/gate-whole-expr.rs index efce28e1d5bb2..63772d54b531d 100644 --- a/src/test/ui/if-attrs/gate-whole-expr.rs +++ b/src/test/ui/if-attrs/gate-whole-expr.rs @@ -1,15 +1,15 @@ // run-pass fn main() { - let x = 1; + let x = 1; - #[cfg(FALSE)] - if false { - x = 2; - } else if true { - x = 3; - } else { - x = 4; - } - assert_eq!(x, 1); + #[cfg(FALSE)] + if false { + x = 2; + } else if true { + x = 3; + } else { + x = 4; + } + assert_eq!(x, 1); } From e50fd5a3dc587b5b970b6b969eff7e8547dede70 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 4 Mar 2020 16:54:16 -0500 Subject: [PATCH 11/32] Update stderr --- .../ui/parser/attr-stmt-expr-attr-bad.stderr | 94 +++++++------------ 1 file changed, 35 insertions(+), 59 deletions(-) diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr index b03db85422d0c..3cc3a455c12fc 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr @@ -136,14 +136,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:41:32 - | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; } - | ^^^^^^^ - error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:43:37 + --> $DIR/attr-stmt-expr-attr-bad.rs:41:37 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` @@ -152,7 +146,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:45:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:43:38 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } | ^^^^^^^^ @@ -160,13 +154,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:47:40 + --> $DIR/attr-stmt-expr-attr-bad.rs:45:40 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:49:45 + --> $DIR/attr-stmt-expr-attr-bad.rs:47:45 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } | ^ --- help: try placing this code inside a block: `{ {}; }` @@ -174,21 +168,15 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } | expected `{` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:51:46 + --> $DIR/attr-stmt-expr-attr-bad.rs:49:46 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:53:45 - | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } - | ^^^^^^^ - error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:53:45 + --> $DIR/attr-stmt-expr-attr-bad.rs:51:45 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } | ^ -------- help: try placing this code inside a block: `{ if 0 {}; }` @@ -196,7 +184,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } | expected `{` error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:56:50 + --> $DIR/attr-stmt-expr-attr-bad.rs:53:50 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` @@ -205,21 +193,15 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:58:51 + --> $DIR/attr-stmt-expr-attr-bad.rs:55:51 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:60:32 - | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; } - | ^^^^^^^ - error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:62:45 + --> $DIR/attr-stmt-expr-attr-bad.rs:57:45 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` @@ -228,7 +210,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:64:46 + --> $DIR/attr-stmt-expr-attr-bad.rs:59:46 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } | ^^^^^^^^ @@ -236,13 +218,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:66:48 + --> $DIR/attr-stmt-expr-attr-bad.rs:61:48 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:68:53 + --> $DIR/attr-stmt-expr-attr-bad.rs:63:53 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } | ^ --- help: try placing this code inside a block: `{ {}; }` @@ -250,21 +232,15 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } | expected `{` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:70:54 + --> $DIR/attr-stmt-expr-attr-bad.rs:65:54 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:72:53 - | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } - | ^^^^^^^ - error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:72:53 + --> $DIR/attr-stmt-expr-attr-bad.rs:67:53 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } | ^ ---------------- help: try placing this code inside a block: `{ if let _ = 0 {}; }` @@ -272,7 +248,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {} | expected `{` error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:75:66 + --> $DIR/attr-stmt-expr-attr-bad.rs:69:66 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` @@ -281,7 +257,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {} | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:77:67 + --> $DIR/attr-stmt-expr-attr-bad.rs:71:67 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } | ^^^^^^^^ @@ -289,7 +265,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]} = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:80:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:74:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } | ------- ^^^^^^^^ not permitted following an outer attibute @@ -299,7 +275,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:82:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:76:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } | ------- ^^^^^^^^ not permitted following an outer attibute @@ -309,7 +285,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:84:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:78:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } | ------- ^^^^^^^^ not permitted following an outer attibute @@ -319,7 +295,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:86:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:80:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } | ------- ^^^^^^^^ not permitted following an outer attibute @@ -329,7 +305,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:88:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:82:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } | ------- ^^^^^^^^ not permitted following an outer attibute @@ -339,7 +315,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error[E0586]: inclusive range with no end - --> $DIR/attr-stmt-expr-attr-bad.rs:94:35 + --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^^^ help: use `..` instead @@ -347,13 +323,13 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error: expected one of `=>`, `if`, or `|`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:94:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end - --> $DIR/attr-stmt-expr-attr-bad.rs:97:35 + --> $DIR/attr-stmt-expr-attr-bad.rs:91:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^^^ help: use `..` instead @@ -361,19 +337,19 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error: expected one of `=>`, `if`, or `|`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:97:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:91:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:100:39 + --> $DIR/attr-stmt-expr-attr-bad.rs:94:39 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } | ^ error[E0586]: inclusive range with no end - --> $DIR/attr-stmt-expr-attr-bad.rs:102:35 + --> $DIR/attr-stmt-expr-attr-bad.rs:96:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^^^ help: use `..` instead @@ -381,47 +357,47 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error: expected one of `=>`, `if`, or `|`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:102:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:96:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:106:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:106:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } | ^ expected one of `.`, `;`, `?`, or an operator error: unexpected token: `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:109:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:103:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:109:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:103:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } | ^ expected one of `.`, `;`, `?`, or an operator error: expected statement after outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:114:37 + --> $DIR/attr-stmt-expr-attr-bad.rs:108:37 | LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } } | ^^^^^^^ error: expected statement after outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:116:37 + --> $DIR/attr-stmt-expr-attr-bad.rs:110:37 | LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } } | ^^^^^^^ -error: aborting due to 57 previous errors +error: aborting due to 53 previous errors For more information about this error, try `rustc --explain E0586`. From 0468929ce3f3e142287124a37f3318cc3b53a52b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 08:40:13 +0100 Subject: [PATCH 12/32] move error allocation test to error.rs --- src/librustc/mir/interpret/error.rs | 18 +++++++++++- src/librustc_mir/transform/const_prop.rs | 35 ++++++------------------ 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 28e197b2a7fc1..2310867400cf6 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -354,7 +354,7 @@ pub enum UnsupportedOpInfo<'tcx> { Unsupported(String), /// When const-prop encounters a situation it does not support, it raises this error. - /// This must not allocate for performance reasons. + /// This must not allocate for performance reasons (hence `str`, not `String`). ConstPropUnsupported(&'tcx str), // -- Everything below is not categorized yet -- @@ -612,3 +612,19 @@ impl fmt::Debug for InterpError<'_> { } } } + +impl InterpError<'_> { + /// Some errors allocate to be created as they contain free-from strings. + /// And sometiems we want to be sure that did not happen as it is a + /// waste of resources. + pub fn allocates(&self) -> bool { + match self { + InterpError::MachineStop(_) + | InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) + | InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(_)) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true, + _ => false, + } + } +} diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 0560f77f5c99f..1fea9281b931b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -404,32 +404,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let r = match f(self) { Ok(val) => Some(val), Err(error) => { - use rustc::mir::interpret::{ - InterpError::*, UndefinedBehaviorInfo, UnsupportedOpInfo, - }; - match error.kind { - MachineStop(_) => bug!("ConstProp does not stop"), - - // Some error shouldn't come up because creating them causes - // an allocation, which we should avoid. When that happens, - // dedicated error variants should be introduced instead. - // Only test this in debug builds though to avoid disruptions. - Unsupported(UnsupportedOpInfo::Unsupported(_)) - | Unsupported(UnsupportedOpInfo::ValidationFailure(_)) - | UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) - | UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) - if cfg!(debug_assertions) => - { - bug!("const-prop encountered allocating error: {:?}", error.kind); - } - - Unsupported(_) - | UndefinedBehavior(_) - | InvalidProgram(_) - | ResourceExhaustion(_) => { - // Ignore these errors. - } - } + // Some errors shouldn't come up because creating them causes + // an allocation, which we should avoid. When that happens, + // dedicated error variants should be introduced instead. + // Only test this in debug builds though to avoid disruptions. + debug_assert!( + !error.kind.allocates(), + "const-prop encountered allocating error: {}", + error + ); None } }; From 938f8522ecf6c463bc06503251a23c3ded35ca25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 08:43:03 +0100 Subject: [PATCH 13/32] miri validation: debug-complain about unexpected errors --- src/librustc_mir/interpret/validity.rs | 27 ++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 84717cbeaa9c4..b3de44f36d2b2 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -46,6 +46,8 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr, $details:expr) => {{ match $e { Ok(x) => x, + // We re-throw the error, so we are okay with allocation: + // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where, $details), } }}; @@ -53,6 +55,8 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr) => {{ match $e { Ok(x) => x, + // We re-throw the error, so we are okay with allocation: + // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where), } }}; @@ -359,10 +363,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M format_args!("a dangling {} (created from integer)", kind), self.path ), - _ => throw_validation_failure!( - format_args!("a dangling {} (not entirely in bounds)", kind), - self.path - ), + err_unsup!(PointerOutOfBounds { .. }) | err_unsup!(DanglingPointerDeref) => { + throw_validation_failure!( + format_args!("a dangling {} (not entirely in bounds)", kind), + self.path + ) + } + _ => bug!("Unexpected error during ptr inbounds test: {}", err), } } }; @@ -638,6 +645,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> err_unsup!(ReadPointerAsBytes) => { throw_validation_failure!("a pointer", self.path, "plain (non-pointer) bytes") } + // Propagate upwards (that will also check for unexpected errors). _ => return Err(err), }, } @@ -797,7 +805,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Try to cast to ptr *once* instead of all the time. let op = self.force_op_ptr(op).unwrap_or(op); - // Run it - visitor.visit_value(op) + // Run it. + match visitor.visit_value(op) { + Ok(()) => Ok(()), + Err(err) if matches!(err.kind, err_unsup!(ValidationFailure { .. })) => Err(err), + Err(err) if cfg!(debug_assertions) => { + bug!("Unexpected error during validation: {}", err) + } + Err(err) => Err(err), + } } } From 4971d03ccfe9452753deb84fd958fd0b0e63f156 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Mar 2020 23:31:39 +0100 Subject: [PATCH 14/32] fix some cases of unexpected exceptions leaving validation --- src/librustc/mir/interpret/error.rs | 13 ++-- src/librustc_mir/const_eval/eval_queries.rs | 7 +- src/librustc_mir/interpret/eval_context.rs | 12 +--- src/librustc_mir/interpret/place.rs | 8 +-- src/librustc_mir/interpret/validity.rs | 64 +++++++++++++++---- src/librustc_mir/transform/const_prop.rs | 5 +- src/test/ui/consts/const-eval/dangling.rs | 2 +- src/test/ui/consts/const-eval/dangling.stderr | 2 +- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 6 +- .../ui/consts/const-eval/ub-wide-ptr.stderr | 58 +++++++++++------ .../ui/consts/const-points-to-static.stderr | 2 +- src/test/ui/consts/issue-63952.stderr | 2 +- .../const_refers_to_static.stderr | 4 +- 13 files changed, 122 insertions(+), 63 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 2310867400cf6..731c3ee0d6a0e 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -245,7 +245,7 @@ fn print_backtrace(backtrace: &mut Backtrace) { eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace); } -impl From for InterpErrorInfo<'tcx> { +impl From for InterpErrorInfo<'_> { fn from(err: ErrorHandled) -> Self { match err { ErrorHandled::Reported => err_inval!(ReferencedConstant), @@ -291,7 +291,7 @@ pub enum InvalidProgramInfo<'tcx> { Layout(layout::LayoutError<'tcx>), } -impl fmt::Debug for InvalidProgramInfo<'tcx> { +impl fmt::Debug for InvalidProgramInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InvalidProgramInfo::*; match self { @@ -304,7 +304,7 @@ impl fmt::Debug for InvalidProgramInfo<'tcx> { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo { +pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Ub(String), /// Free-form case for experimental UB. Only for errors that are never caught! @@ -321,9 +321,11 @@ pub enum UndefinedBehaviorInfo { RemainderByZero, /// Overflowing inbounds pointer arithmetic. PointerArithOverflow, + /// Invalid metadata in a wide pointer (using `str` to avoid allocations). + InvalidMeta(&'tcx str), } -impl fmt::Debug for UndefinedBehaviorInfo { +impl fmt::Debug for UndefinedBehaviorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -338,6 +340,7 @@ impl fmt::Debug for UndefinedBehaviorInfo { DivisionByZero => write!(f, "dividing by zero"), RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), + InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), } } } @@ -577,7 +580,7 @@ impl fmt::Debug for ResourceExhaustionInfo { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo), + UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo<'tcx>), diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 7a8e61db6d019..ffbff00cf3760 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -186,7 +186,12 @@ fn validate_and_turn_into_const<'tcx>( if cid.promoted.is_none() { let mut ref_tracking = RefTracking::new(mplace); while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; + ecx.const_validate_operand( + mplace.into(), + path, + &mut ref_tracking, + /*may_ref_to_static*/ is_static, + )?; } } // Now that we validated, turn this into a proper constant. diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e683422e611a8..9b28b7a20c044 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -457,10 +457,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Check if this brought us over the size limit. if size.bytes() >= self.tcx.data_layout().obj_size_bound() { - throw_ub_format!( - "wide pointer metadata contains invalid information: \ - total size is bigger than largest supported object" - ); + throw_ub!(InvalidMeta("total size is bigger than largest supported object")); } Ok(Some((size, align))) } @@ -476,10 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Make sure the slice is not too big. let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| { - err_ub_format!( - "invalid slice: \ - total size is bigger than largest supported object" - ) + err_ub!(InvalidMeta("slice is bigger than largest supported object")) })?; Ok(Some((size, elem.align.abi))) } @@ -685,7 +679,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // invariant -- that is, unless a function somehow has a ptr to // its return place... but the way MIR is currently generated, the // return place is always a local and then this cannot happen. - self.validate_operand(self.place_to_op(return_place)?, vec![], None)?; + self.validate_operand(self.place_to_op(return_place)?)?; } } else { // Uh, that shouldn't happen... the function did not intend to return diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index fff9c740f7e49..a4815b9696ebb 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -689,7 +689,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + self.validate_operand(self.place_to_op(dest)?)?; } Ok(()) @@ -706,7 +706,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None)?; + self.validate_operand(dest.into())?; } Ok(()) @@ -843,7 +843,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + self.validate_operand(self.place_to_op(dest)?)?; } Ok(()) @@ -951,7 +951,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None)?; + self.validate_operand(dest.into())?; } Ok(()) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index b3de44f36d2b2..05bb010959b32 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -171,6 +171,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { path: Vec, ref_tracking_for_consts: Option<&'rt mut RefTracking, Vec>>, + may_ref_to_static: bool, ecx: &'rt InterpCx<'mir, 'tcx, M>, } @@ -324,9 +325,17 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M self.check_wide_ptr_meta(place.meta, place.layout)?; } // Make sure this is dereferenceable and all. - let (size, align) = self - .ecx - .size_and_align_of(place.meta, place.layout)? + let size_and_align = match self.ecx.size_and_align_of(place.meta, place.layout) { + Ok(res) => res, + Err(err) => match err.kind { + err_ub!(InvalidMeta(msg)) => throw_validation_failure!( + format_args!("invalid {} metadata: {}", kind, msg), + self.path + ), + _ => bug!("Unexpected error during ptr size_and_align_of: {}", err), + }, + }; + let (size, align) = size_and_align // for the purpose of validity, consider foreign types to have // alignment and size determined by the layout (size will be 0, // alignment should take attributes into account). @@ -387,6 +396,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { return Ok(()); } + if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { + throw_validation_failure!( + format_args!("a {} pointing to a static variable", kind), + self.path + ); + } } } // Proceed recursively even for ZST, no reason to skip them! @@ -781,26 +796,20 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// This function checks the data at `op`. `op` is assumed to cover valid memory if it - /// is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - /// - /// `ref_tracking_for_consts` can be `None` to avoid recursive checking below references. - /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion) - /// validation (e.g., pointer values are fine in integers at runtime) and various other const - /// specific validation checks. - pub fn validate_operand( + fn validate_operand_internal( &self, op: OpTy<'tcx, M::PointerTag>, path: Vec, ref_tracking_for_consts: Option< &mut RefTracking, Vec>, >, + may_ref_to_static: bool, ) -> InterpResult<'tcx> { - trace!("validate_operand: {:?}, {:?}", *op, op.layout.ty); + trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); // Construct a visitor - let mut visitor = ValidityVisitor { path, ref_tracking_for_consts, ecx: self }; + let mut visitor = + ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self }; // Try to cast to ptr *once* instead of all the time. let op = self.force_op_ptr(op).unwrap_or(op); @@ -815,4 +824,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(err) => Err(err), } } + + /// This function checks the data at `op` to be const-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + /// + /// `ref_tracking` is used to record references that we encounter so that they + /// can be checked recursively by an outside driving loop. + /// + /// `may_ref_to_static` controls whether references are allowed to point to statics. + #[inline(always)] + pub fn const_validate_operand( + &self, + op: OpTy<'tcx, M::PointerTag>, + path: Vec, + ref_tracking: &mut RefTracking, Vec>, + may_ref_to_static: bool, + ) -> InterpResult<'tcx> { + self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static) + } + + /// This function checks the data at `op` to be runtime-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + #[inline(always)] + pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + self.validate_operand_internal(op, vec![], None, false) + } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 1fea9281b931b..a07c8575b300c 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -637,11 +637,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_info: SourceInfo, ) { trace!("attepting to replace {:?} with {:?}", rval, value); - if let Err(e) = self.ecx.validate_operand( + if let Err(e) = self.ecx.const_validate_operand( value, vec![], // FIXME: is ref tracking too expensive? - Some(&mut interpret::RefTracking::empty()), + &mut interpret::RefTracking::empty(), + /*may_ref_to_static*/ true, ) { trace!("validation error, attempt failed: {:?}", e); return; diff --git a/src/test/ui/consts/const-eval/dangling.rs b/src/test/ui/consts/const-eval/dangling.rs index b5d72d46f2861..c6b8e8eb61181 100644 --- a/src/test/ui/consts/const-eval/dangling.rs +++ b/src/test/ui/consts/const-eval/dangling.rs @@ -6,7 +6,7 @@ use std::{mem, usize}; const TEST: () = { unsafe { //~ NOTE let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); let _val = &*slice; //~ ERROR: any use of this value will cause an error - //~^ NOTE: total size is bigger than largest supported object + //~^ NOTE: slice is bigger than largest supported object //~^^ on by default } }; diff --git a/src/test/ui/consts/const-eval/dangling.stderr b/src/test/ui/consts/const-eval/dangling.stderr index 286de08009754..b9ddc93b03b84 100644 --- a/src/test/ui/consts/const-eval/dangling.stderr +++ b/src/test/ui/consts/const-eval/dangling.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const TEST: () = { unsafe { LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); LL | | let _val = &*slice; - | | ^^^^^^^ invalid slice: total size is bigger than largest supported object + | | ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object LL | | LL | | LL | | } }; diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index 26d378847462d..2d48309b72722 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -31,12 +31,16 @@ const STR_VALID: &str = unsafe { mem::transmute((&42u8, 1usize)) }; // bad str const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; //~^ ERROR it is undefined behavior to use this value +const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); +//~^ ERROR it is undefined behavior to use this value // bad str const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // bad str in user-defined unsized type const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value +const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value // invalid UTF-8 const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; @@ -83,7 +87,7 @@ const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute // # raw slice const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw -const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::max_value())) }; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { //~^ ERROR it is undefined behavior to use this value let uninit_len = MaybeUninit:: { uninit: () }; diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr index 22adf0e55ee8c..a562c64b124f9 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -7,7 +7,15 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:35:1 + --> $DIR/ub-wide-ptr.rs:34:1 + | +LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:37:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -15,7 +23,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:38:1 + --> $DIR/ub-wide-ptr.rs:40:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -25,13 +33,21 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:42:1 | +LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:46:1 + | LL | const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:45:1 + --> $DIR/ub-wide-ptr.rs:49:1 | LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 @@ -39,7 +55,7 @@ LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:52:1 + --> $DIR/ub-wide-ptr.rs:56:1 | LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe { LL | | @@ -51,7 +67,7 @@ LL | | }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:58:1 + --> $DIR/ub-wide-ptr.rs:62:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (not entirely in bounds) @@ -59,7 +75,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:61:1 + --> $DIR/ub-wide-ptr.rs:65:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -67,7 +83,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:64:1 + --> $DIR/ub-wide-ptr.rs:68:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (not entirely in bounds) @@ -75,7 +91,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:67:1 + --> $DIR/ub-wide-ptr.rs:71:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -83,7 +99,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3) = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:71:1 + --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected a boolean @@ -91,7 +107,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:77:1 + --> $DIR/ub-wide-ptr.rs:81:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected a boolean @@ -99,7 +115,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:80:1 + --> $DIR/ub-wide-ptr.rs:84:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected a boolean @@ -107,7 +123,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:87:1 + --> $DIR/ub-wide-ptr.rs:91:1 | LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { LL | | @@ -119,7 +135,7 @@ LL | | }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:95:1 + --> $DIR/ub-wide-ptr.rs:99:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -127,7 +143,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:98:1 + --> $DIR/ub-wide-ptr.rs:102:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -135,7 +151,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:101:1 + --> $DIR/ub-wide-ptr.rs:105:1 | LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -143,7 +159,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4u = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:105:1 + --> $DIR/ub-wide-ptr.rs:109:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected a boolean @@ -151,7 +167,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:109:1 + --> $DIR/ub-wide-ptr.rs:113:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -159,7 +175,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:111:1 + --> $DIR/ub-wide-ptr.rs:115:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -167,17 +183,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:117:5 + --> $DIR/ub-wide-ptr.rs:121:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:121:5 + --> $DIR/ub-wide-ptr.rs:125:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N -error: aborting due to 22 previous errors +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-points-to-static.stderr b/src/test/ui/consts/const-points-to-static.stderr index 8949358e29333..f2ca7ff782591 100644 --- a/src/test/ui/consts/const-points-to-static.stderr +++ b/src/test/ui/consts/const-points-to-static.stderr @@ -8,7 +8,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-points-to-static.rs:5:1 | LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/issue-63952.stderr b/src/test/ui/consts/issue-63952.stderr index d5ed970fc3533..5e85be45b1647 100644 --- a/src/test/ui/consts/issue-63952.stderr +++ b/src/test/ui/consts/issue-63952.stderr @@ -8,7 +8,7 @@ LL | | ptr: &42, ... | LL | | .slice LL | | }; - | |__^ invalid slice: total size is bigger than largest supported object + | |__^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index 15e13942481c9..ad777cfe8ea4b 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -48,7 +48,7 @@ LL | | static FOO: AtomicUsize = AtomicUsize::new(0); LL | | unsafe { &*(&FOO as *const _ as *const usize) } LL | | LL | | }; - | |__^ constant accesses static + | |__^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -97,7 +97,7 @@ LL | | static FOO: usize = 0; LL | | &FOO LL | | LL | | }; - | |__^ constant accesses static + | |__^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. From 85e1466232eadd2ec6b9c2ae0aa4030a39fde04f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 11:30:57 +0100 Subject: [PATCH 15/32] Fix typo Co-Authored-By: bjorn3 --- src/librustc/mir/interpret/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 731c3ee0d6a0e..5869c76345a19 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -617,8 +617,8 @@ impl fmt::Debug for InterpError<'_> { } impl InterpError<'_> { - /// Some errors allocate to be created as they contain free-from strings. - /// And sometiems we want to be sure that did not happen as it is a + /// Some errors allocate to be created as they contain free-form strings. + /// And sometimes we want to be sure that did not happen as it is a /// waste of resources. pub fn allocates(&self) -> bool { match self { From ed3014a2b9470a89165f2762ba746ee7736d5590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 18:14:41 +0100 Subject: [PATCH 16/32] use static strings instead of tcx --- src/librustc/mir/interpret/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 5869c76345a19..b46095927b709 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -304,7 +304,7 @@ impl fmt::Debug for InvalidProgramInfo<'_> { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo<'tcx> { +pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! Ub(String), /// Free-form case for experimental UB. Only for errors that are never caught! @@ -322,10 +322,10 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Overflowing inbounds pointer arithmetic. PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). - InvalidMeta(&'tcx str), + InvalidMeta(&'static str), } -impl fmt::Debug for UndefinedBehaviorInfo<'_> { +impl fmt::Debug for UndefinedBehaviorInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -358,7 +358,7 @@ pub enum UnsupportedOpInfo<'tcx> { /// When const-prop encounters a situation it does not support, it raises this error. /// This must not allocate for performance reasons (hence `str`, not `String`). - ConstPropUnsupported(&'tcx str), + ConstPropUnsupported(&'static str), // -- Everything below is not categorized yet -- FunctionAbiMismatch(Abi, Abi), @@ -580,7 +580,7 @@ impl fmt::Debug for ResourceExhaustionInfo { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), + UndefinedBehavior(UndefinedBehaviorInfo), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo<'tcx>), From af0c44cb2908989159322a4f2bf6ce046a7be5fc Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 09:11:40 +0900 Subject: [PATCH 17/32] Add test for issue-54239 --- .../issue-54239-private-type-triggers-lint.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs diff --git a/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs b/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs new file mode 100644 index 0000000000000..16cf7ad52e4f9 --- /dev/null +++ b/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs @@ -0,0 +1,17 @@ +// Regression test for #54239, shouldn't trigger lint. +// check-pass +// edition:2018 + +#![deny(missing_debug_implementations)] + +struct DontLookAtMe(i32); + +async fn secret() -> DontLookAtMe { + DontLookAtMe(41) +} + +pub async fn looking() -> i32 { // Shouldn't trigger lint here. + secret().await.0 +} + +fn main() {} From fc8be08a8e786514819ffff7c4239879afb8ea3c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 09:11:58 +0900 Subject: [PATCH 18/32] Add test for issue-57200 --- src/test/ui/impl-trait/issue-57200.rs | 14 ++++++++++++++ src/test/ui/impl-trait/issue-57200.stderr | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-57200.rs create mode 100644 src/test/ui/impl-trait/issue-57200.stderr diff --git a/src/test/ui/impl-trait/issue-57200.rs b/src/test/ui/impl-trait/issue-57200.rs new file mode 100644 index 0000000000000..9a7290b3b7524 --- /dev/null +++ b/src/test/ui/impl-trait/issue-57200.rs @@ -0,0 +1,14 @@ +// Regression test for #57200 + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +fn bug<'a, 'b, T>() +where + 'a: 'b, +{ + let f: impl Fn(&'a T) -> &'b T = |x| x; + //~^ ERROR: lifetimes in impl Trait types in bindings are not currently supported +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-57200.stderr b/src/test/ui/impl-trait/issue-57200.stderr new file mode 100644 index 0000000000000..42fd0045315cd --- /dev/null +++ b/src/test/ui/impl-trait/issue-57200.stderr @@ -0,0 +1,8 @@ +error: lifetimes in impl Trait types in bindings are not currently supported + --> $DIR/issue-57200.rs:10:12 + | +LL | let f: impl Fn(&'a T) -> &'b T = |x| x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 437c07f6621739037e52560f54a880acaaaf27ac Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 09:12:06 +0900 Subject: [PATCH 19/32] Add test for issue-57201 --- src/test/ui/impl-trait/issue-57201.rs | 14 ++++++++++++++ src/test/ui/impl-trait/issue-57201.stderr | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-57201.rs create mode 100644 src/test/ui/impl-trait/issue-57201.stderr diff --git a/src/test/ui/impl-trait/issue-57201.rs b/src/test/ui/impl-trait/issue-57201.rs new file mode 100644 index 0000000000000..79b19b52d2061 --- /dev/null +++ b/src/test/ui/impl-trait/issue-57201.rs @@ -0,0 +1,14 @@ +// Regression test for #57201 + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +fn bug<'a, 'b, T>() +where + 'a: 'b, +{ + let f: &impl Fn(&'a T) -> &'b T = &|x| x; + //~^ ERROR: lifetimes in impl Trait types in bindings are not currently supported +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-57201.stderr b/src/test/ui/impl-trait/issue-57201.stderr new file mode 100644 index 0000000000000..5defd15b6b545 --- /dev/null +++ b/src/test/ui/impl-trait/issue-57201.stderr @@ -0,0 +1,8 @@ +error: lifetimes in impl Trait types in bindings are not currently supported + --> $DIR/issue-57201.rs:10:13 + | +LL | let f: &impl Fn(&'a T) -> &'b T = &|x| x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 0005f29d89e9b5ab59f9159acb7aab51b5dad187 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 09:12:25 +0900 Subject: [PATCH 20/32] Add test for issue-60473 --- src/test/ui/impl-trait/issue-60473.rs | 16 ++++++++++++++++ src/test/ui/impl-trait/issue-60473.stderr | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-60473.rs create mode 100644 src/test/ui/impl-trait/issue-60473.stderr diff --git a/src/test/ui/impl-trait/issue-60473.rs b/src/test/ui/impl-trait/issue-60473.rs new file mode 100644 index 0000000000000..596d8a2dd741a --- /dev/null +++ b/src/test/ui/impl-trait/issue-60473.rs @@ -0,0 +1,16 @@ +// Regression test for #60473 + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +struct A<'a>(&'a ()); + +trait Trait { +} + +impl Trait for () { +} + +fn main() { + let x: impl Trait = (); //~ ERROR: opaque type expands to a recursive type +} diff --git a/src/test/ui/impl-trait/issue-60473.stderr b/src/test/ui/impl-trait/issue-60473.stderr new file mode 100644 index 0000000000000..6a07f29727c1d --- /dev/null +++ b/src/test/ui/impl-trait/issue-60473.stderr @@ -0,0 +1,11 @@ +error[E0720]: opaque type expands to a recursive type + --> $DIR/issue-60473.rs:15:12 + | +LL | let x: impl Trait = (); + | ^^^^^^^^^^^^^ expands to a recursive type + | + = note: type resolves to itself + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. From 95d478546ff3b3b3f533e6b86274bde432148ab3 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 09:12:41 +0900 Subject: [PATCH 21/32] Add test for issue-64620 --- src/test/ui/generator/issue-64620-yield-array-element.rs | 9 +++++++++ .../ui/generator/issue-64620-yield-array-element.stderr | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/ui/generator/issue-64620-yield-array-element.rs create mode 100644 src/test/ui/generator/issue-64620-yield-array-element.stderr diff --git a/src/test/ui/generator/issue-64620-yield-array-element.rs b/src/test/ui/generator/issue-64620-yield-array-element.rs new file mode 100644 index 0000000000000..2cbe8f5161465 --- /dev/null +++ b/src/test/ui/generator/issue-64620-yield-array-element.rs @@ -0,0 +1,9 @@ +// Regression test for #64620 + +#![feature(generators)] + +pub fn crash(arr: [usize; 1]) { + yield arr[0]; //~ ERROR: yield expression outside of generator literal +} + +fn main() {} diff --git a/src/test/ui/generator/issue-64620-yield-array-element.stderr b/src/test/ui/generator/issue-64620-yield-array-element.stderr new file mode 100644 index 0000000000000..48383c2ed0824 --- /dev/null +++ b/src/test/ui/generator/issue-64620-yield-array-element.stderr @@ -0,0 +1,9 @@ +error[E0627]: yield expression outside of generator literal + --> $DIR/issue-64620-yield-array-element.rs:6:5 + | +LL | yield arr[0]; + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0627`. From 579ce86d4b813c89eb8a483f79c427565b06c7d2 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 09:12:53 +0900 Subject: [PATCH 22/32] Add test for issue-67166 --- src/test/ui/impl-trait/issue-67166.rs | 11 +++++++++++ src/test/ui/impl-trait/issue-67166.stderr | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-67166.rs create mode 100644 src/test/ui/impl-trait/issue-67166.stderr diff --git a/src/test/ui/impl-trait/issue-67166.rs b/src/test/ui/impl-trait/issue-67166.rs new file mode 100644 index 0000000000000..a877d4cfe3bd7 --- /dev/null +++ b/src/test/ui/impl-trait/issue-67166.rs @@ -0,0 +1,11 @@ +// Regression test for #67166 + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +pub fn run() { + let _foo: Box = Box::new(()); + //~^ ERROR: opaque type expands to a recursive type +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-67166.stderr b/src/test/ui/impl-trait/issue-67166.stderr new file mode 100644 index 0000000000000..abf30f67d5f89 --- /dev/null +++ b/src/test/ui/impl-trait/issue-67166.stderr @@ -0,0 +1,11 @@ +error[E0720]: opaque type expands to a recursive type + --> $DIR/issue-67166.rs:7:19 + | +LL | let _foo: Box = Box::new(()); + | ^^^^^^^^^^^^^^ expands to a recursive type + | + = note: type resolves to itself + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. From 58303b77e0f7b35edd6791b6000cfbaef9cc1cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 6 Mar 2020 00:00:00 +0000 Subject: [PATCH 23/32] Use slices in preference to 0-terminated strings Additionally whenever possible match C API provided by the LLVM. --- .../debuginfo/metadata.rs | 247 ++++++++++-------- src/librustc_codegen_llvm/debuginfo/mod.rs | 22 +- .../debuginfo/namespace.rs | 12 +- src/librustc_codegen_llvm/llvm/ffi.rs | 26 +- src/rustllvm/RustWrapper.cpp | 146 ++++++----- 5 files changed, 266 insertions(+), 187 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 19bd0b6f7e674..5cf3d74f243cd 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -37,7 +37,6 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::const_cstr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_fs_util::path_to_c_string; use rustc_hir::def::CtorKind; @@ -49,7 +48,6 @@ use rustc_target::abi::HasDataLayout; use libc::{c_longlong, c_uint}; use std::collections::hash_map::Entry; -use std::ffi::CString; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; use std::iter; @@ -227,11 +225,14 @@ impl TypeMap<'ll, 'tcx> { /// Gets the unique type ID string for an enum variant part. /// Variant parts are not types and shouldn't really have their own ID, /// but it makes `set_members_of_composite_type()` simpler. - fn get_unique_type_id_str_of_enum_variant_part(&mut self, enum_type_id: UniqueTypeId) -> &str { + fn get_unique_type_id_str_of_enum_variant_part( + &mut self, + enum_type_id: UniqueTypeId, + ) -> String { let variant_part_type_id = format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)); - let interner_key = self.unique_id_interner.intern(&variant_part_type_id); - self.unique_id_interner.get(interner_key) + self.unique_id_interner.intern(&variant_part_type_id); + variant_part_type_id } } @@ -640,9 +641,11 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp // type is going to see *something* weird - the only // question is what exactly it will see. let (size, align) = cx.size_and_align_of(t); + let name = ""; llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - SmallCStr::new("").as_ptr(), + name.as_ptr().cast(), + name.len(), size.bits(), align.bits() as u32, DW_ATE_unsigned, @@ -786,16 +789,17 @@ fn file_metadata_raw( let (file_name, directory) = v.key(); debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory); - let file_name = SmallCStr::new(if let Some(file_name) = file_name { - &file_name - } else { - "" - }); - let directory = - SmallCStr::new(if let Some(directory) = directory { &directory } else { "" }); + let file_name = file_name.as_deref().unwrap_or(""); + let directory = directory.as_deref().unwrap_or(""); let file_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), directory.as_ptr()) + llvm::LLVMRustDIBuilderCreateFile( + DIB(cx), + file_name.as_ptr().cast(), + file_name.len(), + directory.as_ptr().cast(), + directory.len(), + ) }; v.insert(file_metadata); @@ -819,11 +823,11 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { }; let (size, align) = cx.size_and_align_of(t); - let name = SmallCStr::new(name); let ty_metadata = unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr(), + name.as_ptr().cast(), + name.len(), size.bits(), align.bits() as u32, encoding, @@ -851,14 +855,15 @@ fn pointer_type_metadata( ) -> &'ll DIType { let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false); - let name = SmallCStr::new(&name); unsafe { llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_metadata, pointer_size.bits(), pointer_align.bits() as u32, - name.as_ptr(), + 0, // Ignore DWARF address space. + name.as_ptr().cast(), + name.len(), ) } } @@ -889,11 +894,9 @@ pub fn compile_unit_metadata( let producer = format!("clang LLVM ({})", rustc_producer); let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); - let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo); - let work_dir = SmallCStr::new(&tcx.sess.working_dir.0.to_string_lossy()); - let producer = CString::new(producer).unwrap(); + let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let flags = "\0"; - let split_name = "\0"; + let split_name = ""; // FIXME(#60020): // @@ -916,19 +919,23 @@ pub fn compile_unit_metadata( unsafe { let file_metadata = llvm::LLVMRustDIBuilderCreateFile( debug_context.builder, - name_in_debuginfo.as_ptr(), - work_dir.as_ptr(), + name_in_debuginfo.as_ptr().cast(), + name_in_debuginfo.len(), + work_dir.as_ptr().cast(), + work_dir.len(), ); let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( debug_context.builder, DW_LANG_RUST, file_metadata, - producer.as_ptr(), + producer.as_ptr().cast(), + producer.len(), tcx.sess.opts.optimize != config::OptLevel::No, flags.as_ptr().cast(), 0, split_name.as_ptr().cast(), + split_name.len(), kind, ); @@ -1021,12 +1028,12 @@ impl<'ll> MemberDescription<'ll> { cx: &CodegenCx<'ll, '_>, composite_type_metadata: &'ll DIScope, ) -> &'ll DIType { - let member_name = CString::new(self.name).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), composite_type_metadata, - member_name.as_ptr(), + self.name.as_ptr().cast(), + self.name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, self.size.bits(), @@ -1827,9 +1834,13 @@ fn prepare_enum_metadata( let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(cx.tcx), rustc_span::DUMMY_SP); + let item_name; let discriminant_name = match enum_type.kind { - ty::Adt(..) => SmallCStr::new(&cx.tcx.item_name(enum_def_id).as_str()), - ty::Generator(..) => SmallCStr::new(&enum_name), + ty::Adt(..) => { + item_name = cx.tcx.item_name(enum_def_id).as_str(); + &*item_name + } + ty::Generator(..) => enum_name.as_str(), _ => bug!(), }; @@ -1837,7 +1848,8 @@ fn prepare_enum_metadata( llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, - discriminant_name.as_ptr(), + discriminant_name.as_ptr().cast(), + discriminant_name.len(), file_metadata, UNKNOWN_LINE_NUMBER, discriminant_size.bits(), @@ -1872,11 +1884,6 @@ fn prepare_enum_metadata( _ => {} } - let enum_name = SmallCStr::new(&enum_name); - let unique_type_id_str = SmallCStr::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id), - ); - if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { layout::Variants::Single { .. } @@ -1891,20 +1898,27 @@ fn prepare_enum_metadata( } => Some(discriminant_type_metadata(discr.value)), }; - let enum_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name.as_ptr(), - file_metadata, - UNKNOWN_LINE_NUMBER, - layout.size.bits(), - layout.align.abi.bits() as u32, - DIFlags::FlagZero, - None, - 0, // RuntimeLang - unique_type_id_str.as_ptr(), - ) + let enum_metadata = { + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + + unsafe { + llvm::LLVMRustDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr().cast(), + enum_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + DIFlags::FlagZero, + None, + 0, // RuntimeLang + unique_type_id_str.as_ptr().cast(), + unique_type_id_str.len(), + ) + } }; return create_and_register_recursive_type_forward_declaration( @@ -1924,10 +1938,9 @@ fn prepare_enum_metadata( } let discriminator_name = match &enum_type.kind { - ty::Generator(..) => Some(SmallCStr::new(&"__state")), - _ => None, + ty::Generator(..) => "__state", + _ => "", }; - let discriminator_name = discriminator_name.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()); let discriminator_metadata = match layout.variants { // A single-variant enum has no discriminant. layout::Variants::Single { .. } => None, @@ -1955,7 +1968,8 @@ fn prepare_enum_metadata( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - discriminator_name, + discriminator_name.as_ptr().cast(), + discriminator_name.len(), file_metadata, UNKNOWN_LINE_NUMBER, size.bits(), @@ -1981,7 +1995,8 @@ fn prepare_enum_metadata( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - discriminator_name, + discriminator_name.as_ptr().cast(), + discriminator_name.len(), file_metadata, UNKNOWN_LINE_NUMBER, size.bits(), @@ -2010,18 +2025,18 @@ fn prepare_enum_metadata( } }; - let variant_part_unique_type_id_str = SmallCStr::new( - debug_context(cx) - .type_map - .borrow_mut() - .get_unique_type_id_str_of_enum_variant_part(unique_type_id), - ); + let variant_part_unique_type_id_str = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_str_of_enum_variant_part(unique_type_id); let empty_array = create_DIArray(DIB(cx), &[]); + let name = ""; let variant_part = unsafe { llvm::LLVMRustDIBuilderCreateVariantPart( DIB(cx), containing_scope, - ptr::null_mut(), + name.as_ptr().cast(), + name.len(), file_metadata, UNKNOWN_LINE_NUMBER, layout.size.bits(), @@ -2029,29 +2044,38 @@ fn prepare_enum_metadata( DIFlags::FlagZero, discriminator_metadata, empty_array, - variant_part_unique_type_id_str.as_ptr(), + variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.len(), ) }; outer_fields.push(Some(variant_part)); - // The variant part must be wrapped in a struct according to DWARF. - let type_array = create_DIArray(DIB(cx), &outer_fields); - let struct_wrapper = unsafe { - llvm::LLVMRustDIBuilderCreateStructType( - DIB(cx), - Some(containing_scope), - enum_name.as_ptr(), - file_metadata, - UNKNOWN_LINE_NUMBER, - layout.size.bits(), - layout.align.abi.bits() as u32, - DIFlags::FlagZero, - None, - type_array, - 0, - None, - unique_type_id_str.as_ptr(), - ) + let struct_wrapper = { + // The variant part must be wrapped in a struct according to DWARF. + let type_array = create_DIArray(DIB(cx), &outer_fields); + + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + + unsafe { + llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + Some(containing_scope), + enum_name.as_ptr().cast(), + enum_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + DIFlags::FlagZero, + None, + type_array, + 0, + None, + unique_type_id_str.as_ptr().cast(), + unique_type_id_str.len(), + ) + } }; return create_and_register_recursive_type_forward_declaration( @@ -2156,12 +2180,13 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&' cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, rustc_span::DUMMY_SP); - let name = SmallCStr::new(&name.as_str()); + let name = &name.as_str(); Some(unsafe { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), actual_type_metadata, unknown_file_metadata(cx), 0, @@ -2200,10 +2225,9 @@ fn create_struct_stub( ) -> &'ll DICompositeType { let (struct_size, struct_align) = cx.size_and_align_of(struct_type); - let name = SmallCStr::new(struct_type_name); - let unique_type_id = SmallCStr::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id), - ); + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + let metadata_stub = unsafe { // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions @@ -2213,7 +2237,8 @@ fn create_struct_stub( llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, - name.as_ptr(), + struct_type_name.as_ptr().cast(), + struct_type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, struct_size.bits(), @@ -2223,7 +2248,8 @@ fn create_struct_stub( empty_array, 0, None, - unique_type_id.as_ptr(), + unique_type_id.as_ptr().cast(), + unique_type_id.len(), ) }; @@ -2239,10 +2265,9 @@ fn create_union_stub( ) -> &'ll DICompositeType { let (union_size, union_align) = cx.size_and_align_of(union_type); - let name = SmallCStr::new(union_type_name); - let unique_type_id = SmallCStr::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id), - ); + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + let metadata_stub = unsafe { // `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions @@ -2252,7 +2277,8 @@ fn create_union_stub( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, - name.as_ptr(), + union_type_name.as_ptr().cast(), + union_type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, union_size.bits(), @@ -2260,7 +2286,8 @@ fn create_union_stub( DIFlags::FlagZero, Some(empty_array), 0, // RuntimeLang - unique_type_id.as_ptr(), + unique_type_id.as_ptr().cast(), + unique_type_id.len(), ) }; @@ -2294,13 +2321,15 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global let is_local_to_unit = is_node_local_to_unit(cx, def_id); let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx); let type_metadata = type_metadata(cx, variable_type, span); - let var_name = SmallCStr::new(&tcx.item_name(def_id).as_str()); + let var_name = tcx.item_name(def_id).as_str(); let linkage_name = if no_mangle { None } else { - let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); - Some(SmallCStr::new(&linkage_name.name.as_str())) + Some(mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str()) }; + // When empty, linkage_name field is omitted, + // which is what we want for no_mangle statics + let linkage_name = linkage_name.as_deref().unwrap_or(""); let global_align = cx.align_of(variable_type); @@ -2308,10 +2337,10 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), Some(var_scope), - var_name.as_ptr(), - // If null, linkage_name field is omitted, - // which is what we want for no_mangle statics - linkage_name.as_ref().map_or(ptr::null(), |name| name.as_ptr()), + var_name.as_ptr().cast(), + var_name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), file_metadata, line_number, type_metadata, @@ -2339,8 +2368,7 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & // pointer will lead to hard to trace and debug LLVM assertions // later on in `llvm/lib/IR/Value.cpp`. let empty_array = create_DIArray(DIB(cx), &[]); - - let name = const_cstr!("vtable"); + let name = "vtable"; // Create a new one each time. We don't want metadata caching // here, because each vtable will refer to a unique containing @@ -2348,7 +2376,8 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), NO_SCOPE_METADATA, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, Size::ZERO.bits(), @@ -2358,14 +2387,18 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & empty_array, 0, Some(type_metadata), - name.as_ptr(), + name.as_ptr().cast(), + name.len(), ); + let linkage_name = ""; llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, - name.as_ptr(), - ptr::null(), + name.as_ptr().cast(), + name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, vtable_type, diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index a68441f14cb9d..8deab1be3d3a9 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -25,13 +25,11 @@ use rustc::ty::{self, Instance, ParamEnv, Ty}; use rustc_codegen_ssa::debuginfo::type_names; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_index::vec::IndexVec; use libc::c_uint; use log::debug; use std::cell::RefCell; -use std::ffi::CString; use rustc::ty::layout::{self, HasTyCtxt, LayoutOf, Size}; use rustc_ast::ast; @@ -273,13 +271,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Get the linkage_name, which is just the symbol name let linkage_name = mangled_name_of_instance(self, instance); + let linkage_name = linkage_name.name.as_str(); // FIXME(eddyb) does this need to be separate from `loc.line` for some reason? let scope_line = loc.line; - let function_name = CString::new(name).unwrap(); - let linkage_name = SmallCStr::new(&linkage_name.name.as_str()); - let mut flags = DIFlags::FlagPrototyped; if fn_abi.ret.layout.abi.is_uninhabited() { @@ -303,8 +299,10 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateFunction( DIB(self), containing_scope, - function_name.as_ptr(), - linkage_name.as_ptr(), + name.as_ptr().cast(), + name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), file_metadata, loc.line as c_uint, function_type_metadata, @@ -424,12 +422,13 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, rustc_span::DUMMY_SP); - let name = SmallCStr::new(&name.as_str()); + let name = name.as_str(); Some(unsafe { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), actual_type_metadata, file_metadata, 0, @@ -542,13 +541,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { }; let align = self.align_of(variable_type); - let name = SmallCStr::new(&variable_name.as_str()); + let name = variable_name.as_str(); unsafe { llvm::LLVMRustDIBuilderCreateVariable( DIB(self), dwarf_tag, scope_metadata, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), file_metadata, loc.line as c_uint, type_metadata, diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs index 582f495207455..55a3540809b48 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -1,6 +1,5 @@ // Namespace Handling. -use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{debug_context, DIB}; use rustc::ty::{self, Instance}; @@ -10,8 +9,6 @@ use crate::llvm::debuginfo::DIScope; use rustc::hir::map::DefPathData; use rustc_hir::def_id::DefId; -use rustc_data_structures::small_c_str::SmallCStr; - pub fn mangled_name_of_instance<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>, @@ -34,16 +31,15 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), data => data.as_symbol(), }; - - let namespace_name = SmallCStr::new(&namespace_name.as_str()); + let namespace_name = namespace_name.as_str(); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( DIB(cx), parent_scope, - namespace_name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, + namespace_name.as_ptr().cast(), + namespace_name.len(), + false, // ExportSymbols (only relevant for C++ anonymous namespaces) ) }; diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 8b796e0423b13..31a0f52809088 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1607,17 +1607,21 @@ extern "C" { Lang: c_uint, File: &'a DIFile, Producer: *const c_char, + ProducerLen: size_t, isOptimized: bool, Flags: *const c_char, RuntimeVer: c_uint, SplitName: *const c_char, + SplitNameLen: size_t, kind: DebugEmissionKind, ) -> &'a DIDescriptor; pub fn LLVMRustDIBuilderCreateFile( Builder: &DIBuilder<'a>, Filename: *const c_char, + FilenameLen: size_t, Directory: *const c_char, + DirectoryLen: size_t, ) -> &'a DIFile; pub fn LLVMRustDIBuilderCreateSubroutineType( @@ -1630,7 +1634,9 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIDescriptor, Name: *const c_char, + NameLen: size_t, LinkageName: *const c_char, + LinkageNameLen: size_t, File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, @@ -1645,6 +1651,7 @@ extern "C" { pub fn LLVMRustDIBuilderCreateBasicType( Builder: &DIBuilder<'a>, Name: *const c_char, + NameLen: size_t, SizeInBits: u64, AlignInBits: u32, Encoding: c_uint, @@ -1655,13 +1662,16 @@ extern "C" { PointeeTy: &'a DIType, SizeInBits: u64, AlignInBits: u32, + AddressSpace: c_uint, Name: *const c_char, + NameLen: size_t, ) -> &'a DIDerivedType; pub fn LLVMRustDIBuilderCreateStructType( Builder: &DIBuilder<'a>, Scope: Option<&'a DIDescriptor>, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1672,12 +1682,14 @@ extern "C" { RunTimeLang: c_uint, VTableHolder: Option<&'a DIType>, UniqueId: *const c_char, + UniqueIdLen: size_t, ) -> &'a DICompositeType; pub fn LLVMRustDIBuilderCreateMemberType( Builder: &DIBuilder<'a>, Scope: &'a DIDescriptor, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNo: c_uint, SizeInBits: u64, @@ -1691,6 +1703,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1719,7 +1732,9 @@ extern "C" { Builder: &DIBuilder<'a>, Context: Option<&'a DIScope>, Name: *const c_char, + NameLen: size_t, LinkageName: *const c_char, + LinkageNameLen: size_t, File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, @@ -1734,6 +1749,7 @@ extern "C" { Tag: c_uint, Scope: &'a DIDescriptor, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, @@ -1785,6 +1801,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1798,6 +1815,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1806,12 +1824,14 @@ extern "C" { Elements: Option<&'a DIArray>, RunTimeLang: c_uint, UniqueId: *const c_char, + UniqueIdLen: size_t, ) -> &'a DIType; pub fn LLVMRustDIBuilderCreateVariantPart( Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNo: c_uint, SizeInBits: u64, @@ -1820,6 +1840,7 @@ extern "C" { Discriminator: Option<&'a DIDerivedType>, Elements: &'a DIArray, UniqueId: *const c_char, + UniqueIdLen: size_t, ) -> &'a DIDerivedType; pub fn LLVMSetUnnamedAddr(GlobalVar: &Value, UnnamedAddr: Bool); @@ -1828,6 +1849,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: Option<&'a DIScope>, Name: *const c_char, + NameLen: size_t, Ty: &'a DIType, File: &'a DIFile, LineNo: c_uint, @@ -1838,8 +1860,8 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: Option<&'a DIScope>, Name: *const c_char, - File: &'a DIFile, - LineNo: c_uint, + NameLen: size_t, + ExportSymbols: bool, ) -> &'a DINameSpace; pub fn LLVMRustDICompositeTypeReplaceArrays( diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 0e430d3881e60..aeddd4cfb9fe9 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -665,20 +665,24 @@ extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, - const char *Producer, bool isOptimized, const char *Flags, - unsigned RuntimeVer, const char *SplitName, + const char *Producer, size_t ProducerLen, bool isOptimized, + const char *Flags, unsigned RuntimeVer, + const char *SplitName, size_t SplitNameLen, LLVMRustDebugEmissionKind Kind) { auto *File = unwrapDI(FileRef); - return wrap(Builder->createCompileUnit(Lang, File, Producer, isOptimized, - Flags, RuntimeVer, SplitName, + return wrap(Builder->createCompileUnit(Lang, File, StringRef(Producer, ProducerLen), + isOptimized, Flags, RuntimeVer, + StringRef(SplitName, SplitNameLen), fromRust(Kind))); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename, - const char *Directory) { - return wrap(Builder->createFile(Filename, Directory)); +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( + LLVMRustDIBuilderRef Builder, + const char *Filename, size_t FilenameLen, + const char *Directory, size_t DirectoryLen) { + return wrap(Builder->createFile(StringRef(Filename, FilenameLen), + StringRef(Directory, DirectoryLen))); } extern "C" LLVMMetadataRef @@ -690,8 +694,10 @@ LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, - const char *LinkageName, LLVMMetadataRef File, unsigned LineNo, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, + const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMValueRef Fn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) { @@ -705,8 +711,11 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( llvmFlags |= DINode::DIFlags::FlagMainSubprogram; #endif DISubprogram *Sub = Builder->createFunction( - unwrapDI(Scope), Name, LinkageName, unwrapDI(File), - LineNo, unwrapDI(Ty), ScopeLine, llvmFlags, + unwrapDI(Scope), + StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), + unwrapDI(File), LineNo, + unwrapDI(Ty), ScopeLine, llvmFlags, llvmSPFlags, TParams, unwrapDIPtr(Decl)); #else bool IsLocalToUnit = isSet(SPFlags & LLVMRustDISPFlags::SPFlagLocalToUnit); @@ -716,8 +725,11 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) llvmFlags |= DINode::DIFlags::FlagMainSubprogram; DISubprogram *Sub = Builder->createFunction( - unwrapDI(Scope), Name, LinkageName, unwrapDI(File), - LineNo, unwrapDI(Ty), IsLocalToUnit, IsDefinition, + unwrapDI(Scope), + StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), + unwrapDI(File), LineNo, + unwrapDI(Ty), IsLocalToUnit, IsDefinition, ScopeLine, llvmFlags, IsOptimized, TParams, unwrapDIPtr(Decl)); #endif @@ -725,53 +737,59 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( return wrap(Sub); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, - uint64_t SizeInBits, uint32_t AlignInBits, - unsigned Encoding) { - return wrap(Builder->createBasicType(Name, SizeInBits, Encoding)); +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType( + LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding) { + return wrap(Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( LLVMRustDIBuilderRef Builder, LLVMMetadataRef PointeeTy, - uint64_t SizeInBits, uint32_t AlignInBits, const char *Name) { + uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, + const char *Name, size_t NameLen) { return wrap(Builder->createPointerType(unwrapDI(PointeeTy), SizeInBits, AlignInBits, - /* DWARFAddressSpace */ None, - Name)); + AddressSpace, + StringRef(Name, NameLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang, LLVMMetadataRef VTableHolder, - const char *UniqueId) { + const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createStructType( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), unwrapDI(DerivedFrom), DINodeArray(unwrapDI(Elements)), RunTimeLang, - unwrapDI(VTableHolder), UniqueId)); + unwrapDI(VTableHolder), StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator, - LLVMMetadataRef Elements, const char *UniqueId) { + LLVMMetadataRef Elements, const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createVariantPart( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), unwrapDI(Discriminator), - DINodeArray(unwrapDI(Elements)), UniqueId)); + DINodeArray(unwrapDI(Elements)), StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { - return wrap(Builder->createMemberType(unwrapDI(Scope), Name, + return wrap(Builder->createMemberType(unwrapDI(Scope), + StringRef(Name, NameLen), unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, fromRust(Flags), unwrapDI(Ty))); @@ -779,14 +797,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, + uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { llvm::ConstantInt* D = nullptr; if (Discriminant) { D = unwrap(Discriminant); } - return wrap(Builder->createVariantMemberType(unwrapDI(Scope), Name, + return wrap(Builder->createVariantMemberType(unwrapDI(Scope), + StringRef(Name, NameLen), unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, D, fromRust(Flags), unwrapDI(Ty))); @@ -808,8 +827,10 @@ LLVMRustDIBuilderCreateLexicalBlockFile(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name, - const char *LinkageName, LLVMMetadataRef File, unsigned LineNo, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, + const char *Name, size_t NameLen, + const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { llvm::GlobalVariable *InitVal = cast(unwrap(V)); @@ -825,7 +846,8 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( } llvm::DIGlobalVariableExpression *VarExpr = Builder->createGlobalVariableExpression( - unwrapDI(Context), Name, LinkageName, + unwrapDI(Context), StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, #if LLVM_VERSION_GE(10, 0) /* isDefined */ true, @@ -843,17 +865,20 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, - const char *Name, LLVMMetadataRef File, unsigned LineNo, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags, unsigned ArgNo, uint32_t AlignInBits) { if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( - unwrapDI(Scope), Name, unwrapDI(File), LineNo, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits)); } else { return wrap(Builder->createParameterVariable( - unwrapDI(Scope), Name, ArgNo, unwrapDI(File), - LineNo, unwrapDI(Ty), AlwaysPreserve, fromRust(Flags))); + unwrapDI(Scope), StringRef(Name, NameLen), ArgNo, + unwrapDI(File), LineNo, + unwrapDI(Ty), AlwaysPreserve, fromRust(Flags))); } } @@ -894,47 +919,50 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, int64_t Value, bool IsUnsigned) { - return wrap(Builder->createEnumerator({Name, NameLen}, Value, IsUnsigned)); + return wrap(Builder->createEnumerator(StringRef(Name, NameLen), Value, IsUnsigned)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef Elements, LLVMMetadataRef ClassTy, bool IsScoped) { return wrap(Builder->createEnumerationType( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNumber, SizeInBits, AlignInBits, DINodeArray(unwrapDI(Elements)), unwrapDI(ClassTy), "", IsScoped)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Elements, - unsigned RunTimeLang, const char *UniqueId) { + unsigned RunTimeLang, const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createUnionType( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, - SizeInBits, AlignInBits, fromRust(Flags), - DINodeArray(unwrapDI(Elements)), RunTimeLang, UniqueId)); + unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(File), + LineNumber, SizeInBits, AlignInBits, fromRust(Flags), + DINodeArray(unwrapDI(Elements)), RunTimeLang, + StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef Ty, LLVMMetadataRef File, unsigned LineNo, unsigned ColumnNo) { return wrap(Builder->createTemplateTypeParameter( - unwrapDI(Scope), Name, unwrapDI(Ty))); + unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(Ty))); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef Scope, const char *Name, - LLVMMetadataRef File, unsigned LineNo) { +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace( + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, bool ExportSymbols) { return wrap(Builder->createNameSpace( - unwrapDI(Scope), Name, - false // ExportSymbols (only relevant for C++ anonymous namespaces) - )); + unwrapDI(Scope), StringRef(Name, NameLen), ExportSymbols + )); } extern "C" void From e54a829b5795ff137e280628566e44edebe6f14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 6 Mar 2020 00:00:00 +0000 Subject: [PATCH 24/32] Avoid unnecessary interning of enum variant part id --- src/librustc_codegen_llvm/debuginfo/metadata.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 5cf3d74f243cd..46c4a51111432 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -229,10 +229,7 @@ impl TypeMap<'ll, 'tcx> { &mut self, enum_type_id: UniqueTypeId, ) -> String { - let variant_part_type_id = - format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)); - self.unique_id_interner.intern(&variant_part_type_id); - variant_part_type_id + format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)) } } From 676b9bc477dfe58971b7df9df4e3a053bb187dee Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 3 Mar 2020 15:04:57 -0800 Subject: [PATCH 25/32] unix: Don't override existing SIGSEGV/BUS handlers Although `stack_overflow::init` runs very early in the process, even before `main`, there may already be signal handlers installed for things like the address sanitizer. In that case, just leave it alone, and don't bother trying to allocate our own signal stacks either. --- src/libstd/sys/unix/stack_overflow.rs | 28 +++++++++++++++++++-------- src/test/ui/sanitize/badfree.rs | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/sanitize/badfree.rs diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 528fe321efbce..9e8be55075578 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -13,6 +13,10 @@ impl Handler { pub unsafe fn new() -> Handler { make_handler() } + + fn null() -> Handler { + Handler { _data: crate::ptr::null_mut() } + } } impl Drop for Handler { @@ -108,13 +112,20 @@ mod imp { } static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); + static mut NEED_ALTSTACK: bool = false; pub unsafe fn init() { let mut action: sigaction = mem::zeroed(); - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - sigaction(SIGSEGV, &action, ptr::null_mut()); - sigaction(SIGBUS, &action, ptr::null_mut()); + for &signal in &[SIGSEGV, SIGBUS] { + sigaction(signal, ptr::null_mut(), &mut action); + // Configure our signal handler if one is not already set. + if action.sa_sigaction == SIG_DFL { + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + action.sa_sigaction = signal_handler as sighandler_t; + sigaction(signal, &action, ptr::null_mut()); + NEED_ALTSTACK = true; + } + } let handler = make_handler(); MAIN_ALTSTACK = handler._data; @@ -152,6 +163,9 @@ mod imp { } pub unsafe fn make_handler() -> Handler { + if !NEED_ALTSTACK { + return Handler::null(); + } let mut stack = mem::zeroed(); sigaltstack(ptr::null(), &mut stack); // Configure alternate signal stack, if one is not already set. @@ -160,7 +174,7 @@ mod imp { sigaltstack(&stack, ptr::null_mut()); Handler { _data: stack.ss_sp as *mut libc::c_void } } else { - Handler { _data: ptr::null_mut() } + Handler::null() } } @@ -191,14 +205,12 @@ mod imp { target_os = "openbsd" )))] mod imp { - use crate::ptr; - pub unsafe fn init() {} pub unsafe fn cleanup() {} pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } + super::Handler::null() } pub unsafe fn drop_handler(_handler: &mut super::Handler) {} diff --git a/src/test/ui/sanitize/badfree.rs b/src/test/ui/sanitize/badfree.rs new file mode 100644 index 0000000000000..1ca082c8b4704 --- /dev/null +++ b/src/test/ui/sanitize/badfree.rs @@ -0,0 +1,19 @@ +// needs-sanitizer-support +// only-x86_64 +// +// compile-flags: -Z sanitizer=address -O +// +// run-fail +// error-pattern: AddressSanitizer: SEGV + +use std::ffi::c_void; + +extern "C" { + fn free(ptr: *mut c_void); +} + +fn main() { + unsafe { + free(1 as *mut c_void); + } +} From ef98ec055ea30466a83f0b0efb2e40ebd3f89011 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 9 Mar 2020 16:50:46 +0900 Subject: [PATCH 26/32] Add FIXMEs --- src/test/ui/impl-trait/issue-57200.rs | 1 + src/test/ui/impl-trait/issue-57200.stderr | 2 +- src/test/ui/impl-trait/issue-57201.rs | 1 + src/test/ui/impl-trait/issue-57201.stderr | 2 +- src/test/ui/impl-trait/issue-60473.rs | 3 ++- src/test/ui/impl-trait/issue-60473.stderr | 2 +- src/test/ui/impl-trait/issue-67166.rs | 2 +- src/test/ui/impl-trait/issue-67166.stderr | 2 +- 8 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/ui/impl-trait/issue-57200.rs b/src/test/ui/impl-trait/issue-57200.rs index 9a7290b3b7524..e0c71d1ac9a61 100644 --- a/src/test/ui/impl-trait/issue-57200.rs +++ b/src/test/ui/impl-trait/issue-57200.rs @@ -1,4 +1,5 @@ // Regression test for #57200 +// FIXME: The error is temporary hack, we'll revisit here at some point. #![feature(impl_trait_in_bindings)] #![allow(incomplete_features)] diff --git a/src/test/ui/impl-trait/issue-57200.stderr b/src/test/ui/impl-trait/issue-57200.stderr index 42fd0045315cd..b44f332d58ccd 100644 --- a/src/test/ui/impl-trait/issue-57200.stderr +++ b/src/test/ui/impl-trait/issue-57200.stderr @@ -1,5 +1,5 @@ error: lifetimes in impl Trait types in bindings are not currently supported - --> $DIR/issue-57200.rs:10:12 + --> $DIR/issue-57200.rs:11:12 | LL | let f: impl Fn(&'a T) -> &'b T = |x| x; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/issue-57201.rs b/src/test/ui/impl-trait/issue-57201.rs index 79b19b52d2061..c1a98d8897bfb 100644 --- a/src/test/ui/impl-trait/issue-57201.rs +++ b/src/test/ui/impl-trait/issue-57201.rs @@ -1,4 +1,5 @@ // Regression test for #57201 +// FIXME: The error is temporary hack, we'll revisit here at some point. #![feature(impl_trait_in_bindings)] #![allow(incomplete_features)] diff --git a/src/test/ui/impl-trait/issue-57201.stderr b/src/test/ui/impl-trait/issue-57201.stderr index 5defd15b6b545..462b17bf45e2f 100644 --- a/src/test/ui/impl-trait/issue-57201.stderr +++ b/src/test/ui/impl-trait/issue-57201.stderr @@ -1,5 +1,5 @@ error: lifetimes in impl Trait types in bindings are not currently supported - --> $DIR/issue-57201.rs:10:13 + --> $DIR/issue-57201.rs:11:13 | LL | let f: &impl Fn(&'a T) -> &'b T = &|x| x; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/issue-60473.rs b/src/test/ui/impl-trait/issue-60473.rs index 596d8a2dd741a..50cf0c8c6d641 100644 --- a/src/test/ui/impl-trait/issue-60473.rs +++ b/src/test/ui/impl-trait/issue-60473.rs @@ -12,5 +12,6 @@ impl Trait for () { } fn main() { - let x: impl Trait = (); //~ ERROR: opaque type expands to a recursive type + let x: impl Trait = (); // FIXME: The error doesn't seem correct. + //~^ ERROR: opaque type expands to a recursive type } diff --git a/src/test/ui/impl-trait/issue-60473.stderr b/src/test/ui/impl-trait/issue-60473.stderr index 6a07f29727c1d..2d95be4e52c61 100644 --- a/src/test/ui/impl-trait/issue-60473.stderr +++ b/src/test/ui/impl-trait/issue-60473.stderr @@ -1,7 +1,7 @@ error[E0720]: opaque type expands to a recursive type --> $DIR/issue-60473.rs:15:12 | -LL | let x: impl Trait = (); +LL | let x: impl Trait = (); // FIXME: The error doesn't seem correct. | ^^^^^^^^^^^^^ expands to a recursive type | = note: type resolves to itself diff --git a/src/test/ui/impl-trait/issue-67166.rs b/src/test/ui/impl-trait/issue-67166.rs index a877d4cfe3bd7..de7433a9bfc4c 100644 --- a/src/test/ui/impl-trait/issue-67166.rs +++ b/src/test/ui/impl-trait/issue-67166.rs @@ -4,7 +4,7 @@ #![allow(incomplete_features)] pub fn run() { - let _foo: Box = Box::new(()); + let _foo: Box = Box::new(()); // FIXME: The error doesn't much make sense. //~^ ERROR: opaque type expands to a recursive type } diff --git a/src/test/ui/impl-trait/issue-67166.stderr b/src/test/ui/impl-trait/issue-67166.stderr index abf30f67d5f89..56cba3cff0b55 100644 --- a/src/test/ui/impl-trait/issue-67166.stderr +++ b/src/test/ui/impl-trait/issue-67166.stderr @@ -1,7 +1,7 @@ error[E0720]: opaque type expands to a recursive type --> $DIR/issue-67166.rs:7:19 | -LL | let _foo: Box = Box::new(()); +LL | let _foo: Box = Box::new(()); // FIXME: The error doesn't much make sense. | ^^^^^^^^^^^^^^ expands to a recursive type | = note: type resolves to itself From 925e9a2188dcd6e1988ceaa3ab8d64fcdb3d6d1e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 4 Mar 2020 23:37:52 +0300 Subject: [PATCH 27/32] rustc_parse: Use `Token::ident` where possible --- src/librustc_builtin_macros/format.rs | 65 ++++++++++++------------ src/librustc_expand/mbe/macro_parser.rs | 18 +++---- src/librustc_parse/parser/diagnostics.rs | 12 +++-- src/librustc_parse/parser/expr.rs | 50 +++++++++--------- src/librustc_parse/parser/item.rs | 19 +++---- src/librustc_parse/parser/mod.rs | 8 +-- src/librustc_parse/parser/path.rs | 6 +-- 7 files changed, 86 insertions(+), 92 deletions(-) diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs index 1baec5eafe687..2883159a9f34c 100644 --- a/src/librustc_builtin_macros/format.rs +++ b/src/librustc_builtin_macros/format.rs @@ -156,44 +156,43 @@ fn parse_args<'a>( if p.token == token::Eof { break; } // accept trailing commas - if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) { - named = true; - let name = if let token::Ident(name, _) = p.normalized_token.kind { + match p.token.ident() { + Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => { + named = true; p.bump(); - name - } else { - unreachable!(); - }; + p.expect(&token::Eq)?; + let e = p.parse_expr()?; + if let Some(prev) = names.get(&ident.name) { + ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) + .span_label(args[*prev].span, "previously here") + .span_label(e.span, "duplicate argument") + .emit(); + continue; + } - p.expect(&token::Eq)?; - let e = p.parse_expr()?; - if let Some(prev) = names.get(&name) { - ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name)) - .span_label(args[*prev].span, "previously here") - .span_label(e.span, "duplicate argument") - .emit(); - continue; + // Resolve names into slots early. + // Since all the positional args are already seen at this point + // if the input is valid, we can simply append to the positional + // args. And remember the names. + let slot = args.len(); + names.insert(ident.name, slot); + args.push(e); } - - // Resolve names into slots early. - // Since all the positional args are already seen at this point - // if the input is valid, we can simply append to the positional - // args. And remember the names. - let slot = args.len(); - names.insert(name, slot); - args.push(e); - } else { - let e = p.parse_expr()?; - if named { - let mut err = ecx - .struct_span_err(e.span, "positional arguments cannot follow named arguments"); - err.span_label(e.span, "positional arguments must be before named arguments"); - for pos in names.values() { - err.span_label(args[*pos].span, "named argument"); + _ => { + let e = p.parse_expr()?; + if named { + let mut err = ecx.struct_span_err( + e.span, + "positional arguments cannot follow named arguments", + ); + err.span_label(e.span, "positional arguments must be before named arguments"); + for pos in names.values() { + err.span_label(args[*pos].span, "named argument"); + } + err.emit(); } - err.emit(); + args.push(e); } - args.push(e); } } Ok((fmtstr, args, names)) diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index d2a5c54aae490..efba3a8ccb1e6 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -750,15 +750,9 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na /// The token is an identifier, but not `_`. /// We prohibit passing `_` to macros expecting `ident` for now. -fn get_macro_name(token: &Token) -> Option<(Name, bool)> { - match token.kind { - token::Ident(name, is_raw) if name != kw::Underscore => Some((name, is_raw)), - token::Interpolated(ref nt) => match **nt { - token::NtIdent(ident, is_raw) if ident.name != kw::Underscore => { - Some((ident.name, is_raw)) - } - _ => None, - }, +fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { + match token.ident() { + Some((ident, is_raw)) if ident.name != kw::Underscore => Some((ident, is_raw)), _ => None, } } @@ -783,7 +777,7 @@ fn may_begin_with(token: &Token, name: Name) -> bool { && !token.is_keyword(kw::Let) } sym::ty => token.can_begin_type(), - sym::ident => get_macro_name(token).is_some(), + sym::ident => get_macro_ident(token).is_some(), sym::literal => token.can_begin_literal_or_bool(), sym::vis => match token.kind { // The follow-set of :vis + "priv" keyword + interpolated @@ -888,9 +882,9 @@ fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a, sym::ty => token::NtTy(p.parse_ty()?), // this could be handled like a token, since it is one sym::ident => { - if let Some((name, is_raw)) = get_macro_name(&p.token) { + if let Some((ident, is_raw)) = get_macro_ident(&p.token) { p.bump(); - token::NtIdent(Ident::new(name, p.normalized_prev_token.span), is_raw) + token::NtIdent(ident, is_raw) } else { let token_str = pprust::token_to_string(&p.token); let msg = &format!("expected ident, found {}", &token_str); diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 6587e763d50c5..7c1df531ad16e 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -192,17 +192,19 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(token::DelimToken::Brace), TokenKind::CloseDelim(token::DelimToken::Paren), ]; - if let token::Ident(name, false) = self.normalized_token.kind { - if Ident::new(name, self.normalized_token.span).is_raw_guess() - && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + match self.token.ident() { + Some((ident, false)) + if ident.is_raw_guess() + && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => { err.span_suggestion( - self.normalized_token.span, + ident.span, "you can escape reserved keywords to use them as identifiers", - format!("r#{}", name), + format!("r#{}", ident.name), Applicability::MaybeIncorrect, ); } + _ => {} } if let Some(token_descr) = super::token_descr_opt(&self.token) { err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index e7c47b0be8e49..66266aa5dc416 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -97,9 +97,10 @@ impl<'a> Parser<'a> { fn parse_expr_catch_underscore(&mut self) -> PResult<'a, P> { match self.parse_expr() { Ok(expr) => Ok(expr), - Err(mut err) => match self.normalized_token.kind { - token::Ident(name, false) - if name == kw::Underscore && self.look_ahead(1, |t| t == &token::Comma) => + Err(mut err) => match self.token.ident() { + Some((ident, false)) + if ident.name == kw::Underscore + && self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` err.emit(); @@ -331,21 +332,19 @@ impl<'a> Parser<'a> { /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. fn check_assoc_op(&self) -> Option> { - Some(Spanned { - node: match (AssocOp::from_token(&self.token), &self.normalized_token.kind) { - (Some(op), _) => op, - (None, token::Ident(sym::and, false)) => { - self.error_bad_logical_op("and", "&&", "conjunction"); - AssocOp::LAnd - } - (None, token::Ident(sym::or, false)) => { - self.error_bad_logical_op("or", "||", "disjunction"); - AssocOp::LOr - } - _ => return None, - }, - span: self.normalized_token.span, - }) + let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { + (Some(op), _) => (op, self.token.span), + (None, Some((ident, false))) if ident.name == sym::and => { + self.error_bad_logical_op("and", "&&", "conjunction"); + (AssocOp::LAnd, ident.span) + } + (None, Some((ident, false))) if ident.name == sym::or => { + self.error_bad_logical_op("or", "||", "disjunction"); + (AssocOp::LOr, ident.span) + } + _ => return None, + }; + Some(source_map::respan(span, op)) } /// Error on `and` and `or` suggesting `&&` and `||` respectively. @@ -1907,20 +1906,23 @@ impl<'a> Parser<'a> { /// Use in case of error after field-looking code: `S { foo: () with a }`. fn find_struct_error_after_field_looking_code(&self) -> Option { - if let token::Ident(name, _) = self.normalized_token.kind { - if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) { - return Some(ast::Field { - ident: Ident::new(name, self.normalized_token.span), + match self.token.ident() { + Some((ident, is_raw)) + if (is_raw || !ident.is_reserved()) + && self.look_ahead(1, |t| *t == token::Colon) => + { + Some(ast::Field { + ident, span: self.token.span, expr: self.mk_expr_err(self.token.span), is_shorthand: false, attrs: AttrVec::new(), id: DUMMY_NODE_ID, is_placeholder: false, - }); + }) } + _ => None, } - None } fn recover_struct_comma_after_dotdot(&mut self, span: Span) { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 01dd2f885ff5e..c1b38591f56c3 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -750,10 +750,10 @@ impl<'a> Parser<'a> { } fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { - match self.normalized_token.kind { - token::Ident(name @ kw::Underscore, false) => { + match self.token.ident() { + Some((ident, false)) if ident.name == kw::Underscore => { self.bump(); - Ok(Ident::new(name, self.normalized_prev_token.span)) + Ok(ident) } _ => self.parse_ident(), } @@ -1609,15 +1609,12 @@ impl<'a> Parser<'a> { /// Returns the parsed optional self parameter and whether a self shortcut was used. fn parse_self_param(&mut self) -> PResult<'a, Option> { // Extract an identifier *after* having confirmed that the token is one. - let expect_self_ident = |this: &mut Self| { - match this.normalized_token.kind { - // Preserve hygienic context. - token::Ident(name, _) => { - this.bump(); - Ident::new(name, this.normalized_prev_token.span) - } - _ => unreachable!(), + let expect_self_ident = |this: &mut Self| match this.token.ident() { + Some((ident, false)) => { + this.bump(); + ident } + _ => unreachable!(), }; // Is `self` `n` tokens ahead? let is_isolated_self = |this: &Self, n| { diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 74101fef8e39b..0e3cee45dcdb0 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -480,9 +480,9 @@ impl<'a> Parser<'a> { } fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { - match self.normalized_token.kind { - token::Ident(name, _) => { - if self.token.is_reserved_ident() { + match self.token.ident() { + Some((ident, is_raw)) => { + if !is_raw && ident.is_reserved() { let mut err = self.expected_ident_found(); if recover { err.emit(); @@ -491,7 +491,7 @@ impl<'a> Parser<'a> { } } self.bump(); - Ok(Ident::new(name, self.normalized_prev_token.span)) + Ok(ident) } _ => Err(match self.prev_token.kind { TokenKind::DocComment(..) => { diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 355b6429a7494..f88b4fe6ff0a8 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -240,10 +240,10 @@ impl<'a> Parser<'a> { } pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> { - match self.normalized_token.kind { - token::Ident(name, _) if name.is_path_segment_keyword() => { + match self.token.ident() { + Some((ident, false)) if ident.is_path_segment_keyword() => { self.bump(); - Ok(Ident::new(name, self.normalized_prev_token.span)) + Ok(ident) } _ => self.parse_ident(), } From f4a03c44d5859dea64dea7fdbaef5377f37c5dd2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 5 Mar 2020 00:34:57 +0300 Subject: [PATCH 28/32] rustc_ast: Introduce `Token::uninterpolated_span` --- src/librustc_ast/attr/mod.rs | 4 ++++ src/librustc_ast/token.rs | 30 ++++++++++++++++++++++++++++++ src/librustc_parse/parser/expr.rs | 17 ++++++++++------- src/librustc_parse/parser/item.rs | 2 +- src/librustc_parse/parser/mod.rs | 6 +++--- src/librustc_parse/parser/ty.rs | 2 +- 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 0638e8e667617..280994116c013 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -286,6 +286,10 @@ impl MetaItem { } impl AttrItem { + pub fn span(&self) -> Span { + self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) + } + pub fn meta(&self, span: Span) -> Option { Some(MetaItem { path: self.path.clone(), diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index a8a2c9b2fb318..c1564882cfe9e 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -328,6 +328,18 @@ impl Token { mem::replace(self, Token::dummy()) } + /// For interpolated tokens returns a span of the fragment to which the interpolated + /// token refers, for all other tokens this is just a regular span. + /// It is particularly important to use this for identifiers and lifetimes + /// for which spans affect name resolution. This also includes edition checks + /// for edition-specific keyword identifiers. + pub fn uninterpolated_span(&self) -> Span { + match &self.kind { + Interpolated(nt) => nt.span(), + _ => self.span, + } + } + pub fn is_op(&self) -> bool { match self.kind { OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) @@ -714,6 +726,24 @@ pub enum Nonterminal { #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(Nonterminal, 40); +impl Nonterminal { + fn span(&self) -> Span { + match self { + NtItem(item) => item.span, + NtBlock(block) => block.span, + NtStmt(stmt) => stmt.span, + NtPat(pat) => pat.span, + NtExpr(expr) | NtLiteral(expr) => expr.span, + NtTy(ty) => ty.span, + NtIdent(ident, _) | NtLifetime(ident) => ident.span, + NtMeta(attr_item) => attr_item.span(), + NtPath(path) => path.span, + NtVis(vis) => vis.span, + NtTT(tt) => tt.span(), + } + } +} + impl PartialEq for Nonterminal { fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 66266aa5dc416..743fc3a4efa1d 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -849,7 +849,7 @@ impl<'a> Parser<'a> { /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { - if self.normalized_token.span.rust_2018() && self.eat_keyword(kw::Await) { + if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) { return self.mk_await_expr(self_arg, lo); } @@ -963,7 +963,7 @@ impl<'a> Parser<'a> { // | ^ expected expression self.bump(); Ok(self.mk_expr_err(self.token.span)) - } else if self.normalized_token.span.rust_2018() { + } else if self.token.uninterpolated_span().rust_2018() { // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. if self.check_keyword(kw::Async) { if self.is_async_block() { @@ -1396,11 +1396,14 @@ impl<'a> Parser<'a> { let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; - let asyncness = - if self.normalized_token.span.rust_2018() { self.parse_asyncness() } else { Async::No }; - if asyncness.is_async() { + let asyncness = if self.token.uninterpolated_span().rust_2018() { + self.parse_asyncness() + } else { + Async::No + }; + if let Async::Yes { span, .. } = asyncness { // Feature-gate `async ||` closures. - self.sess.gated_spans.gate(sym::async_closure, self.normalized_prev_token.span); + self.sess.gated_spans.gate(sym::async_closure, span); } let capture_clause = self.parse_capture_clause(); @@ -1756,7 +1759,7 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) && self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && - self.normalized_token.span.rust_2018() && + self.token.uninterpolated_span().rust_2018() && // Prevent `while try {} {}`, `if try {} {} else {}`, etc. !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index c1b38591f56c3..232ecd6fdaed1 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -574,7 +574,7 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As)) { self.bump(); // `default` - Defaultness::Default(self.normalized_prev_token.span) + Defaultness::Default(self.prev_token.uninterpolated_span()) } else { Defaultness::Final } diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 0e3cee45dcdb0..252a80431ac36 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -884,7 +884,7 @@ impl<'a> Parser<'a> { /// Parses asyncness: `async` or nothing. fn parse_asyncness(&mut self) -> Async { if self.eat_keyword(kw::Async) { - let span = self.normalized_prev_token.span; + let span = self.prev_token.uninterpolated_span(); Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } } else { Async::No @@ -894,7 +894,7 @@ impl<'a> Parser<'a> { /// Parses unsafety: `unsafe` or nothing. fn parse_unsafety(&mut self) -> Unsafe { if self.eat_keyword(kw::Unsafe) { - Unsafe::Yes(self.normalized_prev_token.span) + Unsafe::Yes(self.prev_token.uninterpolated_span()) } else { Unsafe::No } @@ -903,7 +903,7 @@ impl<'a> Parser<'a> { /// Parses constness: `const` or nothing. fn parse_constness(&mut self) -> Const { if self.eat_keyword(kw::Const) { - Const::Yes(self.normalized_prev_token.span) + Const::Yes(self.prev_token.uninterpolated_span()) } else { Const::No } diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c4469331b6669..16adf5c05a4ee 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -323,7 +323,7 @@ impl<'a> Parser<'a> { /// Is a `dyn B0 + ... + Bn` type allowed here? fn is_explicit_dyn_type(&mut self) -> bool { self.check_keyword(kw::Dyn) - && (self.normalized_token.span.rust_2018() + && (self.token.uninterpolated_span().rust_2018() || self.look_ahead(1, |t| { t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t) })) From 43b27df5b211bc0fae74f34834ae84d17215c5ac Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 14:37:38 +0300 Subject: [PATCH 29/32] rustc_ast: Introduce `Token::uninterpolate` --- src/librustc_ast/token.rs | 20 ++++++++++++++++++-- src/librustc_parse/parser/expr.rs | 4 ++-- src/librustc_parse/parser/item.rs | 4 ++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index c1564882cfe9e..b80694ab6de84 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -14,8 +14,8 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::kw; use rustc_span::symbol::Symbol; use rustc_span::{self, Span, DUMMY_SP}; -use std::fmt; -use std::mem; +use std::borrow::Cow; +use std::{fmt, mem}; #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] #[derive(HashStable_Generic)] @@ -457,6 +457,22 @@ impl Token { } } + // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token + // into the regular identifier or lifetime token it refers to, + // otherwise returns the original token. + pub fn uninterpolate(&self) -> Cow<'_, Token> { + match &self.kind { + Interpolated(nt) => match **nt { + NtIdent(ident, is_raw) => { + Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)) + } + NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), + _ => Cow::Borrowed(self), + }, + _ => Cow::Borrowed(self), + } + } + /// Returns an identifier if this token is an identifier. pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { match self.kind { diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 743fc3a4efa1d..f7cfb028a7a66 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -435,7 +435,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_or_use_outer_attributes(attrs)?; let lo = self.token.span; // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() - let (hi, ex) = match self.normalized_token.kind { + let (hi, ex) = match self.token.uninterpolate().kind { token::Not => self.parse_unary_expr(lo, UnOp::Not), // `!expr` token::Tilde => self.recover_tilde_expr(lo), // `~expr` token::BinOp(token::Minus) => self.parse_unary_expr(lo, UnOp::Neg), // `-expr` @@ -755,7 +755,7 @@ impl<'a> Parser<'a> { } fn parse_dot_suffix_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { - match self.normalized_token.kind { + match self.token.uninterpolate().kind { token::Ident(..) => self.parse_dot_suffix(base, lo), token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => { Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix)) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 232ecd6fdaed1..08d71f03976d6 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1544,7 +1544,7 @@ impl<'a> Parser<'a> { let is_name_required = match self.token.kind { token::DotDotDot => false, - _ => req_name(self.normalized_token.span.edition()), + _ => req_name(self.token.uninterpolate().span.edition()), }; let (pat, ty) = if is_name_required || self.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); @@ -1648,7 +1648,7 @@ impl<'a> Parser<'a> { // Only a limited set of initial token sequences is considered `self` parameters; anything // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.token.span; - let (eself, eself_ident, eself_hi) = match self.normalized_token.kind { + let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind { token::BinOp(token::And) => { let eself = if is_isolated_self(self, 1) { // `&self` From 5d7f67d3b109e95fb0dca8f773a2146db4eb4a93 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 16:34:29 +0300 Subject: [PATCH 30/32] rustc_parse: Remove `Parser::normalized(_prev)_token` --- src/librustc_parse/lib.rs | 5 ++-- src/librustc_parse/parser/mod.rs | 42 ++++---------------------------- 2 files changed, 7 insertions(+), 40 deletions(-) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 25f9f8fd3ad4f..10d524776a11b 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -4,7 +4,7 @@ #![feature(crate_visibility_modifier)] use rustc_ast::ast; -use rustc_ast::token::{self, Nonterminal, Token}; +use rustc_ast::token::{self, Nonterminal}; use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; @@ -171,8 +171,7 @@ fn maybe_source_file_to_parser( let mut parser = stream_to_parser(sess, stream, None); parser.unclosed_delims = unclosed_delims; if parser.token == token::Eof { - let span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); - parser.set_token(Token::new(token::Eof, span)); + parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); } Ok(parser) diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 252a80431ac36..9376c7c1c724d 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -88,21 +88,10 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { #[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, - /// The current non-normalized token. + /// The current token. pub token: Token, - /// The current normalized token. - /// "Normalized" means that some interpolated tokens - /// (`$i: ident` and `$l: lifetime` meta-variables) are replaced - /// with non-interpolated identifier and lifetime tokens they refer to. - /// Use this if you need to check for `token::Ident` or `token::Lifetime` specifically, - /// this also includes edition checks for edition-specific keyword identifiers. - pub normalized_token: Token, - /// The previous non-normalized token. + /// The previous token. pub prev_token: Token, - /// The previous normalized token. - /// Use this if you need to check for `token::Ident` or `token::Lifetime` specifically, - /// this also includes edition checks for edition-specific keyword identifiers. - pub normalized_prev_token: Token, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. pub(super) directory: Directory, @@ -374,9 +363,7 @@ impl<'a> Parser<'a> { let mut parser = Parser { sess, token: Token::dummy(), - normalized_token: Token::dummy(), prev_token: Token::dummy(), - normalized_prev_token: Token::dummy(), restrictions: Restrictions::empty(), recurse_into_file_modules, directory: Directory { @@ -609,7 +596,7 @@ impl<'a> Parser<'a> { Some((first, second)) if first == expected => { let first_span = self.sess.source_map().start_point(self.token.span); let second_span = self.token.span.with_lo(first_span.hi()); - self.set_token(Token::new(first, first_span)); + self.token = Token::new(first, first_span); self.bump_with(Token::new(second, second_span)); true } @@ -817,23 +804,6 @@ impl<'a> Parser<'a> { self.parse_delim_comma_seq(token::Paren, f) } - // Interpolated identifier (`$i: ident`) and lifetime (`$l: lifetime`) - // tokens are replaced with usual identifier and lifetime tokens, - // so the former are never encountered during normal parsing. - crate fn set_token(&mut self, token: Token) { - self.token = token; - self.normalized_token = match &self.token.kind { - token::Interpolated(nt) => match **nt { - token::NtIdent(ident, is_raw) => { - Token::new(token::Ident(ident.name, is_raw), ident.span) - } - token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span), - _ => self.token.clone(), - }, - _ => self.token.clone(), - } - } - /// Advance the parser by one token using provided token as the next one. fn bump_with(&mut self, next_token: Token) { // Bumping after EOF is a bad sign, usually an infinite loop. @@ -843,9 +813,7 @@ impl<'a> Parser<'a> { } // Update the current and previous tokens. - self.prev_token = self.token.take(); - self.normalized_prev_token = self.normalized_token.take(); - self.set_token(next_token); + self.prev_token = mem::replace(&mut self.token, next_token); // Diagnostics. self.expected_tokens.clear(); @@ -1005,7 +973,7 @@ impl<'a> Parser<'a> { &mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap(), ); - self.set_token(Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close)); + self.token = Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close); self.bump(); TokenTree::Delimited(frame.span, frame.delim, frame.tree_cursor.stream) } From 9be233cbfe134f032ed2d50f7cc66e901bbe3f6f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 15:58:27 +0300 Subject: [PATCH 31/32] Use `Token::uninterpolate` in couple more places matching on `(Nt)Ident` --- src/librustc_ast/attr/mod.rs | 5 ++--- src/librustc_ast/token.rs | 32 +++++++++++-------------------- src/librustc_ast/tokenstream.rs | 7 +++++++ src/librustc_ast/util/literal.rs | 15 ++++----------- src/librustc_parse/parser/expr.rs | 3 +-- src/librustc_parse/parser/item.rs | 2 ++ src/librustc_parse/parser/pat.rs | 2 +- 7 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 280994116c013..52a59e82ae23f 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -441,7 +441,7 @@ impl MetaItem { I: Iterator, { // FIXME: Share code with `parse_path`. - let path = match tokens.next() { + let path = match tokens.next().map(TokenTree::uninterpolate) { Some(TokenTree::Token(Token { kind: kind @ token::Ident(..), span })) | Some(TokenTree::Token(Token { kind: kind @ token::ModSep, span })) => 'arm: { let mut segments = if let token::Ident(name, _) = kind { @@ -457,7 +457,7 @@ impl MetaItem { }; loop { if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) = - tokens.next() + tokens.next().map(TokenTree::uninterpolate) { segments.push(PathSegment::from_ident(Ident::new(name, span))); } else { @@ -474,7 +474,6 @@ impl MetaItem { Path { span, segments } } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { - token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index b80694ab6de84..b022d969deccb 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -357,7 +357,7 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { - match self.kind { + match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_expr(name, self.span, is_raw), // value name or keyword OpenDelim(..) | // tuple, array or block @@ -375,12 +375,10 @@ impl Token { Lifetime(..) | // labeled loop Pound => true, // expression attributes Interpolated(ref nt) => match **nt { - NtIdent(ident, is_raw) => ident_can_begin_expr(ident.name, ident.span, is_raw), NtLiteral(..) | NtExpr(..) | NtBlock(..) | - NtPath(..) | - NtLifetime(..) => true, + NtPath(..) => true, _ => false, }, _ => false, @@ -389,7 +387,7 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { - match self.kind { + match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_type(name, self.span, is_raw), // type name or keyword OpenDelim(Paren) | // tuple @@ -403,8 +401,7 @@ impl Token { Lt | BinOp(Shl) | // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtIdent(ident, is_raw) => ident_can_begin_type(ident.name, ident.span, is_raw), - NtTy(..) | NtPath(..) | NtLifetime(..) => true, + NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -445,11 +442,10 @@ impl Token { /// /// Keep this in sync with `Lit::from_token`. pub fn can_begin_literal_or_bool(&self) -> bool { - match self.kind { + match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, Ident(name, false) if name.is_bool_lit() => true, Interpolated(ref nt) => match &**nt { - NtIdent(ident, false) if ident.name.is_bool_lit() => true, NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)), _ => false, }, @@ -475,24 +471,18 @@ impl Token { /// Returns an identifier if this token is an identifier. pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { - match self.kind { - Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)), - Interpolated(ref nt) => match **nt { - NtIdent(ident, is_raw) => Some((ident, is_raw)), - _ => None, - }, + let token = self.uninterpolate(); + match token.kind { + Ident(name, is_raw) => Some((ast::Ident::new(name, token.span), is_raw)), _ => None, } } /// Returns a lifetime identifier if this token is a lifetime. pub fn lifetime(&self) -> Option { - match self.kind { - Lifetime(name) => Some(ast::Ident::new(name, self.span)), - Interpolated(ref nt) => match **nt { - NtLifetime(ident) => Some(ident), - _ => None, - }, + let token = self.uninterpolate(); + match token.kind { + Lifetime(name) => Some(ast::Ident::new(name, token.span)), _ => None, } } diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 03e8fff247b39..916a5ff6f46f4 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -116,6 +116,13 @@ impl TokenTree { pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree { TokenTree::token(token::CloseDelim(delim), span.close) } + + pub fn uninterpolate(self) -> TokenTree { + match self { + TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()), + tt => tt, + } + } } impl HashStable for TokenStream diff --git a/src/librustc_ast/util/literal.rs b/src/librustc_ast/util/literal.rs index ecf17efc4e0d1..d1757394f3a1d 100644 --- a/src/librustc_ast/util/literal.rs +++ b/src/librustc_ast/util/literal.rs @@ -191,23 +191,16 @@ impl Lit { /// /// Keep this in sync with `Token::can_begin_literal_or_bool`. pub fn from_token(token: &Token) -> Result { - let lit = match token.kind { + let lit = match token.uninterpolate().kind { token::Ident(name, false) if name.is_bool_lit() => { token::Lit::new(token::Bool, name, None) } token::Literal(lit) => lit, token::Interpolated(ref nt) => { - match &**nt { - token::NtIdent(ident, false) if ident.name.is_bool_lit() => { - let lit = token::Lit::new(token::Bool, ident.name, None); - return Lit::from_lit_token(lit, ident.span); + if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { + if let ast::ExprKind::Lit(lit) = &expr.kind { + return Ok(lit.clone()); } - token::NtExpr(expr) | token::NtLiteral(expr) => { - if let ast::ExprKind::Lit(lit) = &expr.kind { - return Ok(lit.clone()); - } - } - _ => {} } return Err(LitError::NotLiteral); } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index f7cfb028a7a66..d28b9cd968218 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -50,7 +50,6 @@ macro_rules! maybe_whole_expr { AttrVec::new(), )); } - // N.B., `NtIdent(ident)` is normalized to `Ident` in `fn bump`. _ => {} }; } @@ -482,7 +481,7 @@ impl<'a> Parser<'a> { } fn is_mistaken_not_ident_negation(&self) -> bool { - let token_cannot_continue_expr = |t: &Token| match t.kind { + let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind { // These tokens can start an expression after `!`, but // can't continue an expression after an ident token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw), diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 08d71f03976d6..bf612bfc0e4a1 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1544,6 +1544,8 @@ impl<'a> Parser<'a> { let is_name_required = match self.token.kind { token::DotDotDot => false, + // FIXME: Consider using interpolated token for this edition check, + // it should match the intent of edition hygiene better. _ => req_name(self.token.uninterpolate().span.edition()), }; let (pat, ty) = if is_name_required || self.is_named_param() { diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index 4c041fd669d67..f52a91ff5989d 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -151,7 +151,7 @@ impl<'a> Parser<'a> { /// Note that there are more tokens such as `@` for which we know that the `|` /// is an illegal parse. However, the user's intent is less clear in that case. fn recover_trailing_vert(&mut self, lo: Option) -> bool { - let is_end_ahead = self.look_ahead(1, |token| match &token.kind { + let is_end_ahead = self.look_ahead(1, |token| match &token.uninterpolate().kind { token::FatArrow // e.g. `a | => 0,`. | token::Ident(kw::If, false) // e.g. `a | if expr`. | token::Eq // e.g. `let a | = 0`. From 7a30bb1676690596f73659d18959877d993510ae Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 9 Mar 2020 12:42:33 +0300 Subject: [PATCH 32/32] Address review comments --- src/librustc_ast/token.rs | 19 ++++++++++++++----- src/librustc_expand/mbe/macro_parser.rs | 5 +---- src/librustc_parse/parser/expr.rs | 13 ++++++------- src/librustc_parse/parser/item.rs | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index b022d969deccb..b67b7d346f756 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -225,8 +225,15 @@ pub enum TokenKind { /* Literals */ Literal(Lit), - /* Name components */ + /// Identifier token. + /// Do not forget about `NtIdent` when you want to match on identifiers. + /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to + /// treat regular and interpolated identifiers in the same way. Ident(ast::Name, /* is_raw */ bool), + /// Lifetime identifier token. + /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. + /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to + /// treat regular and interpolated lifetime identifiers in the same way. Lifetime(ast::Name), Interpolated(Lrc), @@ -328,11 +335,12 @@ impl Token { mem::replace(self, Token::dummy()) } - /// For interpolated tokens returns a span of the fragment to which the interpolated - /// token refers, for all other tokens this is just a regular span. + /// For interpolated tokens, returns a span of the fragment to which the interpolated + /// token refers. For all other tokens this is just a regular span. /// It is particularly important to use this for identifiers and lifetimes - /// for which spans affect name resolution. This also includes edition checks - /// for edition-specific keyword identifiers. + /// for which spans affect name resolution and edition checks. + /// Note that keywords are also identifiers, so they should use this + /// if they keep spans or perform edition checks. pub fn uninterpolated_span(&self) -> Span { match &self.kind { Interpolated(nt) => nt.span(), @@ -453,6 +461,7 @@ impl Token { } } + // A convenience function for matching on identifiers during parsing. // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token // into the regular identifier or lifetime token it refers to, // otherwise returns the original token. diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index efba3a8ccb1e6..6d4d7f5b4f394 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -751,10 +751,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na /// The token is an identifier, but not `_`. /// We prohibit passing `_` to macros expecting `ident` for now. fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { - match token.ident() { - Some((ident, is_raw)) if ident.name != kw::Underscore => Some((ident, is_raw)), - _ => None, - } + token.ident().filter(|(ident, _)| ident.name != kw::Underscore) } /// Checks whether a non-terminal may begin with a particular token. diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index d28b9cd968218..bfca9f07f05d5 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -97,9 +97,8 @@ impl<'a> Parser<'a> { match self.parse_expr() { Ok(expr) => Ok(expr), Err(mut err) => match self.token.ident() { - Some((ident, false)) - if ident.name == kw::Underscore - && self.look_ahead(1, |t| t == &token::Comma) => + Some((Ident { name: kw::Underscore, .. }, false)) + if self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` err.emit(); @@ -333,13 +332,13 @@ impl<'a> Parser<'a> { fn check_assoc_op(&self) -> Option> { let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { (Some(op), _) => (op, self.token.span), - (None, Some((ident, false))) if ident.name == sym::and => { + (None, Some((Ident { name: sym::and, span }, false))) => { self.error_bad_logical_op("and", "&&", "conjunction"); - (AssocOp::LAnd, ident.span) + (AssocOp::LAnd, span) } - (None, Some((ident, false))) if ident.name == sym::or => { + (None, Some((Ident { name: sym::or, span }, false))) => { self.error_bad_logical_op("or", "||", "disjunction"); - (AssocOp::LOr, ident.span) + (AssocOp::LOr, span) } _ => return None, }; diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index bf612bfc0e4a1..126686c8defbf 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -751,7 +751,7 @@ impl<'a> Parser<'a> { fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { match self.token.ident() { - Some((ident, false)) if ident.name == kw::Underscore => { + Some((ident @ Ident { name: kw::Underscore, .. }, false)) => { self.bump(); Ok(ident) }