From d4fe9553f65df51a18999e956fd507e26271e74e Mon Sep 17 00:00:00 2001
From: mibac138 <5672750+mibac138@users.noreply.github.com>
Date: Thu, 7 May 2020 03:57:31 +0200
Subject: [PATCH 001/123] Implement partial error recovery for `let` with
`BinOpEq`
When parsing `let x: i8 += 1` the compiler interprets `i8` as a trait
which makes it more complicated to do error recovery. More advanced
error recovery is not implemented in this commit.
---
src/librustc_parse/parser/stmt.rs | 29 ++++++++++++++++++++++--
src/test/ui/parser/let-binop-plus.rs | 7 ++++++
src/test/ui/parser/let-binop-plus.stderr | 9 ++++++++
src/test/ui/parser/let-binop.rs | 8 +++++++
src/test/ui/parser/let-binop.stderr | 21 +++++++++++++++++
5 files changed, 72 insertions(+), 2 deletions(-)
create mode 100644 src/test/ui/parser/let-binop-plus.rs
create mode 100644 src/test/ui/parser/let-binop-plus.stderr
create mode 100644 src/test/ui/parser/let-binop.rs
create mode 100644 src/test/ui/parser/let-binop.stderr
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 849193151c335..049aa7447f4db 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -12,7 +12,7 @@ use rustc_ast::ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKin
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
use rustc_ast::util::classify;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{struct_span_err, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym};
@@ -217,7 +217,32 @@ impl<'a> Parser<'a> {
/// Parses the RHS of a local variable declaration (e.g., '= 14;').
fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option
>> {
- if self.eat(&token::Eq) || skip_eq { Ok(Some(self.parse_expr()?)) } else { Ok(None) }
+ let parse = if !self.eat(&token::Eq) && !skip_eq {
+ // Error recovery for `let x += 1`
+ if matches!(self.token.kind, TokenKind::BinOpEq(_)) {
+ struct_span_err!(
+ self.sess.span_diagnostic,
+ self.token.span,
+ E0067,
+ "can't reassign to a uninitialized variable"
+ )
+ .span_suggestion_short(
+ self.token.span,
+ "replace with `=` to initialize the variable",
+ "=".to_string(),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ self.bump();
+ true
+ } else {
+ false
+ }
+ } else {
+ true
+ };
+
+ if parse { Ok(Some(self.parse_expr()?)) } else { Ok(None) }
}
/// Parses a block. No inner attributes are allowed.
diff --git a/src/test/ui/parser/let-binop-plus.rs b/src/test/ui/parser/let-binop-plus.rs
new file mode 100644
index 0000000000000..8d883d6e24894
--- /dev/null
+++ b/src/test/ui/parser/let-binop-plus.rs
@@ -0,0 +1,7 @@
+#![allow(bare_trait_objects)]
+
+fn main() {
+ let a: i8 += 1;
+ //~^ ERROR expected trait, found builtin type `i8`
+ let _ = a;
+}
diff --git a/src/test/ui/parser/let-binop-plus.stderr b/src/test/ui/parser/let-binop-plus.stderr
new file mode 100644
index 0000000000000..baa935aff713c
--- /dev/null
+++ b/src/test/ui/parser/let-binop-plus.stderr
@@ -0,0 +1,9 @@
+error[E0404]: expected trait, found builtin type `i8`
+ --> $DIR/let-binop-plus.rs:4:12
+ |
+LL | let a: i8 += 1;
+ | ^^ not a trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0404`.
diff --git a/src/test/ui/parser/let-binop.rs b/src/test/ui/parser/let-binop.rs
new file mode 100644
index 0000000000000..d445ab6bb8a1f
--- /dev/null
+++ b/src/test/ui/parser/let-binop.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let a: i8 *= 1; //~ ERROR can't reassign to a uninitialized variable
+ let _ = a;
+ let b += 1; //~ ERROR can't reassign to a uninitialized variable
+ let _ = b;
+ let c *= 1; //~ ERROR can't reassign to a uninitialized variable
+ let _ = c;
+}
diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr
new file mode 100644
index 0000000000000..3e9d4a80a70ef
--- /dev/null
+++ b/src/test/ui/parser/let-binop.stderr
@@ -0,0 +1,21 @@
+error[E0067]: can't reassign to a uninitialized variable
+ --> $DIR/let-binop.rs:2:15
+ |
+LL | let a: i8 *= 1;
+ | ^^ help: replace with `=` to initialize the variable
+
+error[E0067]: can't reassign to a uninitialized variable
+ --> $DIR/let-binop.rs:4:11
+ |
+LL | let b += 1;
+ | ^^ help: replace with `=` to initialize the variable
+
+error[E0067]: can't reassign to a uninitialized variable
+ --> $DIR/let-binop.rs:6:11
+ |
+LL | let c *= 1;
+ | ^^ help: replace with `=` to initialize the variable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0067`.
From 48ff12acb184672393692e087927a66ff7907d71 Mon Sep 17 00:00:00 2001
From: mibac138 <5672750+mibac138@users.noreply.github.com>
Date: Thu, 7 May 2020 04:09:57 +0200
Subject: [PATCH 002/123] Expand partial error recovery for `let` with
`BinOpEq`
---
src/librustc_parse/parser/stmt.rs | 40 +++++++++++++++++++++--------
src/test/ui/parser/let-binop.stderr | 22 ++++++++++++++--
2 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 049aa7447f4db..aceee81432896 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -145,12 +145,12 @@ impl<'a> Parser<'a> {
}
fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
- let local = self.parse_local(attrs)?;
+ let local = self.parse_local(lo, attrs)?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
}
/// Parses a local variable declaration.
- fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> {
+ fn parse_local(&mut self, let_span: Span, attrs: AttrVec) -> PResult<'a, P> {
let lo = self.prev_token.span;
let pat = self.parse_top_pat(GateOr::Yes)?;
@@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
} else {
(None, None)
};
- let init = match (self.parse_initializer(err.is_some()), err) {
+ let init = match (self.parse_initializer(let_span, ty.is_some(), err.is_some()), err) {
(Ok(init), None) => {
// init parsed, ty parsed
init
@@ -216,23 +216,43 @@ impl<'a> Parser<'a> {
}
/// Parses the RHS of a local variable declaration (e.g., '= 14;').
- fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option>> {
+ fn parse_initializer(
+ &mut self,
+ let_span: Span,
+ has_ty: bool,
+ skip_eq: bool,
+ ) -> PResult<'a, Option
>> {
let parse = if !self.eat(&token::Eq) && !skip_eq {
// Error recovery for `let x += 1`
if matches!(self.token.kind, TokenKind::BinOpEq(_)) {
- struct_span_err!(
+ let mut err = struct_span_err!(
self.sess.span_diagnostic,
self.token.span,
E0067,
"can't reassign to a uninitialized variable"
- )
- .span_suggestion_short(
+ );
+ err.span_suggestion_short(
self.token.span,
"replace with `=` to initialize the variable",
"=".to_string(),
- Applicability::MaybeIncorrect,
- )
- .emit();
+ if has_ty {
+ // for `let x: i8 += 1` it's highly likely that the `+` is a typo
+ Applicability::MachineApplicable
+ } else {
+ // for `let x += 1` it's a bit less likely that the `+` is a typo
+ Applicability::MaybeIncorrect
+ },
+ );
+ // In case of code like `let x += 1` it's possible the user may have meant to write `x += 1`
+ if !has_ty {
+ err.span_suggestion_short(
+ let_span,
+ "remove to reassign to a previously initialized variable",
+ "".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
self.bump();
true
} else {
diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr
index 3e9d4a80a70ef..c37612430cef1 100644
--- a/src/test/ui/parser/let-binop.stderr
+++ b/src/test/ui/parser/let-binop.stderr
@@ -8,13 +8,31 @@ error[E0067]: can't reassign to a uninitialized variable
--> $DIR/let-binop.rs:4:11
|
LL | let b += 1;
- | ^^ help: replace with `=` to initialize the variable
+ | ^^
+ |
+help: replace with `=` to initialize the variable
+ |
+LL | let b = 1;
+ | ^
+help: remove to reassign to a previously initialized variable
+ |
+LL | b += 1;
+ | --
error[E0067]: can't reassign to a uninitialized variable
--> $DIR/let-binop.rs:6:11
|
LL | let c *= 1;
- | ^^ help: replace with `=` to initialize the variable
+ | ^^
+ |
+help: replace with `=` to initialize the variable
+ |
+LL | let c = 1;
+ | ^
+help: remove to reassign to a previously initialized variable
+ |
+LL | c *= 1;
+ | --
error: aborting due to 3 previous errors
From 05d653199871955eba90abdd3b176603f030ab60 Mon Sep 17 00:00:00 2001
From: mibac138 <5672750+mibac138@users.noreply.github.com>
Date: Thu, 7 May 2020 05:00:59 +0200
Subject: [PATCH 003/123] Error recovery for `let` with `+=`
---
src/librustc_parse/parser/stmt.rs | 65 ++++++++++++------------
src/test/ui/parser/let-binop-plus.rs | 1 +
src/test/ui/parser/let-binop-plus.stderr | 11 +++-
3 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index aceee81432896..224f4ebf53828 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -222,44 +222,43 @@ impl<'a> Parser<'a> {
has_ty: bool,
skip_eq: bool,
) -> PResult<'a, Option
>> {
- let parse = if !self.eat(&token::Eq) && !skip_eq {
+ // In case of code like `let x: i8 += 1`, `i8` is interpreted as a trait consuming the `+`
+ // from `+=`.
+ let ate_plus = self.prev_token.is_like_plus() && has_ty;
+ let parse = if !skip_eq && (ate_plus || matches!(self.token.kind, TokenKind::BinOpEq(_))) {
// Error recovery for `let x += 1`
- if matches!(self.token.kind, TokenKind::BinOpEq(_)) {
- let mut err = struct_span_err!(
- self.sess.span_diagnostic,
- self.token.span,
- E0067,
- "can't reassign to a uninitialized variable"
- );
+ let mut err = struct_span_err!(
+ self.sess.span_diagnostic,
+ self.token.span,
+ E0067,
+ "can't reassign to a uninitialized variable"
+ );
+ err.span_suggestion_short(
+ self.token.span,
+ "replace with `=` to initialize the variable",
+ "=".to_string(),
+ if has_ty {
+ // for `let x: i8 += 1` it's highly likely that the `+` is a typo
+ Applicability::MachineApplicable
+ } else {
+ // for `let x += 1` it's a bit less likely that the `+` is a typo
+ Applicability::MaybeIncorrect
+ },
+ );
+ // In case of code like `let x += 1` it's possible the user may have meant to write `x += 1`
+ if !has_ty {
err.span_suggestion_short(
- self.token.span,
- "replace with `=` to initialize the variable",
- "=".to_string(),
- if has_ty {
- // for `let x: i8 += 1` it's highly likely that the `+` is a typo
- Applicability::MachineApplicable
- } else {
- // for `let x += 1` it's a bit less likely that the `+` is a typo
- Applicability::MaybeIncorrect
- },
+ let_span,
+ "remove to reassign to a previously initialized variable",
+ "".to_string(),
+ Applicability::MaybeIncorrect,
);
- // In case of code like `let x += 1` it's possible the user may have meant to write `x += 1`
- if !has_ty {
- err.span_suggestion_short(
- let_span,
- "remove to reassign to a previously initialized variable",
- "".to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- err.emit();
- self.bump();
- true
- } else {
- false
}
- } else {
+ err.emit();
+ self.bump();
true
+ } else {
+ self.eat(&token::Eq) || skip_eq
};
if parse { Ok(Some(self.parse_expr()?)) } else { Ok(None) }
diff --git a/src/test/ui/parser/let-binop-plus.rs b/src/test/ui/parser/let-binop-plus.rs
index 8d883d6e24894..98473e9f096d8 100644
--- a/src/test/ui/parser/let-binop-plus.rs
+++ b/src/test/ui/parser/let-binop-plus.rs
@@ -3,5 +3,6 @@
fn main() {
let a: i8 += 1;
//~^ ERROR expected trait, found builtin type `i8`
+ //~| ERROR can't reassign to a uninitialized variable
let _ = a;
}
diff --git a/src/test/ui/parser/let-binop-plus.stderr b/src/test/ui/parser/let-binop-plus.stderr
index baa935aff713c..d7d84ff16a0a1 100644
--- a/src/test/ui/parser/let-binop-plus.stderr
+++ b/src/test/ui/parser/let-binop-plus.stderr
@@ -1,9 +1,16 @@
+error[E0067]: can't reassign to a uninitialized variable
+ --> $DIR/let-binop-plus.rs:4:16
+ |
+LL | let a: i8 += 1;
+ | ^ help: replace with `=` to initialize the variable
+
error[E0404]: expected trait, found builtin type `i8`
--> $DIR/let-binop-plus.rs:4:12
|
LL | let a: i8 += 1;
| ^^ not a trait
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0404`.
+Some errors have detailed explanations: E0067, E0404.
+For more information about an error, try `rustc --explain E0067`.
From 6ad24baf06c687517f188e8c6e6ce848924d001c Mon Sep 17 00:00:00 2001
From: mibac138 <5672750+mibac138@users.noreply.github.com>
Date: Thu, 7 May 2020 23:45:51 +0200
Subject: [PATCH 004/123] Adjust according to estebank's review comments
---
src/librustc_parse/parser/stmt.rs | 19 ++++++++-----------
src/test/ui/parser/let-binop-plus.rs | 2 +-
src/test/ui/parser/let-binop-plus.stderr | 4 ++--
src/test/ui/parser/let-binop.rs | 6 +++---
src/test/ui/parser/let-binop.stderr | 20 ++++++++++----------
5 files changed, 24 insertions(+), 27 deletions(-)
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 224f4ebf53828..bec810fde081d 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -174,7 +174,10 @@ impl<'a> Parser<'a> {
} else {
(None, None)
};
- let init = match (self.parse_initializer(let_span, ty.is_some(), err.is_some()), err) {
+ let init = match (
+ self.parse_initializer(let_span.until(pat.span), ty.is_some(), err.is_some()),
+ err,
+ ) {
(Ok(init), None) => {
// init parsed, ty parsed
init
@@ -231,25 +234,19 @@ impl<'a> Parser<'a> {
self.sess.span_diagnostic,
self.token.span,
E0067,
- "can't reassign to a uninitialized variable"
+ "can't reassign to an uninitialized variable"
);
err.span_suggestion_short(
self.token.span,
- "replace with `=` to initialize the variable",
+ "initialize the variable",
"=".to_string(),
- if has_ty {
- // for `let x: i8 += 1` it's highly likely that the `+` is a typo
- Applicability::MachineApplicable
- } else {
- // for `let x += 1` it's a bit less likely that the `+` is a typo
- Applicability::MaybeIncorrect
- },
+ Applicability::MaybeIncorrect,
);
// In case of code like `let x += 1` it's possible the user may have meant to write `x += 1`
if !has_ty {
err.span_suggestion_short(
let_span,
- "remove to reassign to a previously initialized variable",
+ "otherwise, reassign to a previously initialized variable",
"".to_string(),
Applicability::MaybeIncorrect,
);
diff --git a/src/test/ui/parser/let-binop-plus.rs b/src/test/ui/parser/let-binop-plus.rs
index 98473e9f096d8..4d6d9b5c8d37f 100644
--- a/src/test/ui/parser/let-binop-plus.rs
+++ b/src/test/ui/parser/let-binop-plus.rs
@@ -3,6 +3,6 @@
fn main() {
let a: i8 += 1;
//~^ ERROR expected trait, found builtin type `i8`
- //~| ERROR can't reassign to a uninitialized variable
+ //~| ERROR can't reassign to an uninitialized variable
let _ = a;
}
diff --git a/src/test/ui/parser/let-binop-plus.stderr b/src/test/ui/parser/let-binop-plus.stderr
index d7d84ff16a0a1..91a59fe24fedc 100644
--- a/src/test/ui/parser/let-binop-plus.stderr
+++ b/src/test/ui/parser/let-binop-plus.stderr
@@ -1,8 +1,8 @@
-error[E0067]: can't reassign to a uninitialized variable
+error[E0067]: can't reassign to an uninitialized variable
--> $DIR/let-binop-plus.rs:4:16
|
LL | let a: i8 += 1;
- | ^ help: replace with `=` to initialize the variable
+ | ^ help: initialize the variable
error[E0404]: expected trait, found builtin type `i8`
--> $DIR/let-binop-plus.rs:4:12
diff --git a/src/test/ui/parser/let-binop.rs b/src/test/ui/parser/let-binop.rs
index d445ab6bb8a1f..7f58f5df2d412 100644
--- a/src/test/ui/parser/let-binop.rs
+++ b/src/test/ui/parser/let-binop.rs
@@ -1,8 +1,8 @@
fn main() {
- let a: i8 *= 1; //~ ERROR can't reassign to a uninitialized variable
+ let a: i8 *= 1; //~ ERROR can't reassign to an uninitialized variable
let _ = a;
- let b += 1; //~ ERROR can't reassign to a uninitialized variable
+ let b += 1; //~ ERROR can't reassign to an uninitialized variable
let _ = b;
- let c *= 1; //~ ERROR can't reassign to a uninitialized variable
+ let c *= 1; //~ ERROR can't reassign to an uninitialized variable
let _ = c;
}
diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr
index c37612430cef1..8a90b7cf74a4a 100644
--- a/src/test/ui/parser/let-binop.stderr
+++ b/src/test/ui/parser/let-binop.stderr
@@ -1,37 +1,37 @@
-error[E0067]: can't reassign to a uninitialized variable
+error[E0067]: can't reassign to an uninitialized variable
--> $DIR/let-binop.rs:2:15
|
LL | let a: i8 *= 1;
- | ^^ help: replace with `=` to initialize the variable
+ | ^^ help: initialize the variable
-error[E0067]: can't reassign to a uninitialized variable
+error[E0067]: can't reassign to an uninitialized variable
--> $DIR/let-binop.rs:4:11
|
LL | let b += 1;
| ^^
|
-help: replace with `=` to initialize the variable
+help: initialize the variable
|
LL | let b = 1;
| ^
-help: remove to reassign to a previously initialized variable
+help: otherwise, reassign to a previously initialized variable
|
-LL | b += 1;
+LL | b += 1;
| --
-error[E0067]: can't reassign to a uninitialized variable
+error[E0067]: can't reassign to an uninitialized variable
--> $DIR/let-binop.rs:6:11
|
LL | let c *= 1;
| ^^
|
-help: replace with `=` to initialize the variable
+help: initialize the variable
|
LL | let c = 1;
| ^
-help: remove to reassign to a previously initialized variable
+help: otherwise, reassign to a previously initialized variable
|
-LL | c *= 1;
+LL | c *= 1;
| --
error: aborting due to 3 previous errors
From 98532a30901d7544c49fe82f499db53699645de0 Mon Sep 17 00:00:00 2001
From: mibac138 <5672750+mibac138@users.noreply.github.com>
Date: Wed, 20 May 2020 22:09:03 +0200
Subject: [PATCH 005/123] Adjust according to petrochenkov's review comments
---
src/librustc_parse/parser/stmt.rs | 65 ++++++++----------------
src/test/ui/parser/let-binop-plus.rs | 8 ---
src/test/ui/parser/let-binop-plus.stderr | 16 ------
src/test/ui/parser/let-binop.stderr | 29 ++---------
4 files changed, 27 insertions(+), 91 deletions(-)
delete mode 100644 src/test/ui/parser/let-binop-plus.rs
delete mode 100644 src/test/ui/parser/let-binop-plus.stderr
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index bec810fde081d..53f32b7c800bd 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -12,7 +12,7 @@ use rustc_ast::ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKin
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
use rustc_ast::util::classify;
-use rustc_errors::{struct_span_err, Applicability, PResult};
+use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym};
@@ -145,12 +145,12 @@ impl<'a> Parser<'a> {
}
fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
- let local = self.parse_local(lo, attrs)?;
+ let local = self.parse_local(attrs)?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
}
/// Parses a local variable declaration.
- fn parse_local(&mut self, let_span: Span, attrs: AttrVec) -> PResult<'a, P> {
+ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> {
let lo = self.prev_token.span;
let pat = self.parse_top_pat(GateOr::Yes)?;
@@ -174,10 +174,7 @@ impl<'a> Parser<'a> {
} else {
(None, None)
};
- let init = match (
- self.parse_initializer(let_span.until(pat.span), ty.is_some(), err.is_some()),
- err,
- ) {
+ let init = match (self.parse_initializer(err.is_some()), err) {
(Ok(init), None) => {
// init parsed, ty parsed
init
@@ -219,46 +216,28 @@ impl<'a> Parser<'a> {
}
/// Parses the RHS of a local variable declaration (e.g., '= 14;').
- fn parse_initializer(
- &mut self,
- let_span: Span,
- has_ty: bool,
- skip_eq: bool,
- ) -> PResult<'a, Option>> {
- // In case of code like `let x: i8 += 1`, `i8` is interpreted as a trait consuming the `+`
- // from `+=`.
- let ate_plus = self.prev_token.is_like_plus() && has_ty;
- let parse = if !skip_eq && (ate_plus || matches!(self.token.kind, TokenKind::BinOpEq(_))) {
- // Error recovery for `let x += 1`
- let mut err = struct_span_err!(
- self.sess.span_diagnostic,
- self.token.span,
- E0067,
- "can't reassign to an uninitialized variable"
- );
- err.span_suggestion_short(
- self.token.span,
- "initialize the variable",
- "=".to_string(),
- Applicability::MaybeIncorrect,
- );
- // In case of code like `let x += 1` it's possible the user may have meant to write `x += 1`
- if !has_ty {
- err.span_suggestion_short(
- let_span,
- "otherwise, reassign to a previously initialized variable",
- "".to_string(),
+ fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option
>> {
+ let eq_consumed = match self.token.kind {
+ token::BinOpEq(..) => {
+ // Recover `let x = 1` as `let x = 1`
+ self.struct_span_err(
+ self.token.span,
+ "can't reassign to an uninitialized variable",
+ )
+ .span_suggestion_short(
+ self.token.span,
+ "initialize the variable",
+ "=".to_string(),
Applicability::MaybeIncorrect,
- );
+ )
+ .emit();
+ self.bump();
+ true
}
- err.emit();
- self.bump();
- true
- } else {
- self.eat(&token::Eq) || skip_eq
+ _ => self.eat(&token::Eq),
};
- if parse { Ok(Some(self.parse_expr()?)) } else { Ok(None) }
+ Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None })
}
/// Parses a block. No inner attributes are allowed.
diff --git a/src/test/ui/parser/let-binop-plus.rs b/src/test/ui/parser/let-binop-plus.rs
deleted file mode 100644
index 4d6d9b5c8d37f..0000000000000
--- a/src/test/ui/parser/let-binop-plus.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![allow(bare_trait_objects)]
-
-fn main() {
- let a: i8 += 1;
- //~^ ERROR expected trait, found builtin type `i8`
- //~| ERROR can't reassign to an uninitialized variable
- let _ = a;
-}
diff --git a/src/test/ui/parser/let-binop-plus.stderr b/src/test/ui/parser/let-binop-plus.stderr
deleted file mode 100644
index 91a59fe24fedc..0000000000000
--- a/src/test/ui/parser/let-binop-plus.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0067]: can't reassign to an uninitialized variable
- --> $DIR/let-binop-plus.rs:4:16
- |
-LL | let a: i8 += 1;
- | ^ help: initialize the variable
-
-error[E0404]: expected trait, found builtin type `i8`
- --> $DIR/let-binop-plus.rs:4:12
- |
-LL | let a: i8 += 1;
- | ^^ not a trait
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0067, E0404.
-For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr
index 8a90b7cf74a4a..71431499ac70b 100644
--- a/src/test/ui/parser/let-binop.stderr
+++ b/src/test/ui/parser/let-binop.stderr
@@ -1,39 +1,20 @@
-error[E0067]: can't reassign to an uninitialized variable
+error: can't reassign to an uninitialized variable
--> $DIR/let-binop.rs:2:15
|
LL | let a: i8 *= 1;
| ^^ help: initialize the variable
-error[E0067]: can't reassign to an uninitialized variable
+error: can't reassign to an uninitialized variable
--> $DIR/let-binop.rs:4:11
|
LL | let b += 1;
- | ^^
- |
-help: initialize the variable
- |
-LL | let b = 1;
- | ^
-help: otherwise, reassign to a previously initialized variable
- |
-LL | b += 1;
- | --
+ | ^^ help: initialize the variable
-error[E0067]: can't reassign to an uninitialized variable
+error: can't reassign to an uninitialized variable
--> $DIR/let-binop.rs:6:11
|
LL | let c *= 1;
- | ^^
- |
-help: initialize the variable
- |
-LL | let c = 1;
- | ^
-help: otherwise, reassign to a previously initialized variable
- |
-LL | c *= 1;
- | --
+ | ^^ help: initialize the variable
error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0067`.
From 730f7366bba5abdf5ae0c2f1222795e40d48f90c Mon Sep 17 00:00:00 2001
From: Benjamin Saunders
Date: Fri, 22 May 2020 20:49:20 -0700
Subject: [PATCH 006/123] Fix asinh of negative values
When `x` has large magnitude, `x + ((x * x) + 1.0).sqrt()` approaches
`x + x.abs()`. For negative values of `x`, this leads to catastrophic
cancellation, resulting in large errors or even 0 being passed to
`ln`, producing incorrect results including `-inf`.
Becuase asinh is an odd function, i.e. -asinh(x) = asinh(-x) for all
x, we can avoid the catastrophic cancellation and obtain correct
results by taking the absolute value of `self` for the first
term. `self * self` is always positive, so in effect this gives us
`x.abs().asinh().copysign(x)` which as discussed above is
algebraically equivalent, but is much more accurate.
---
src/libstd/f32.rs | 4 +++-
src/libstd/f64.rs | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 8e743ace99bfb..ab468f42b3bd0 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -835,7 +835,7 @@ impl f32 {
if self == Self::NEG_INFINITY {
Self::NEG_INFINITY
} else {
- (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
+ (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
}
}
@@ -1414,6 +1414,8 @@ mod tests {
assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
+ // regression test for the catastrophic cancellation fixed in 72486
+ assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
}
#[test]
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index fe64d27b1efc8..c033198f021c2 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -837,7 +837,7 @@ impl f64 {
if self == Self::NEG_INFINITY {
Self::NEG_INFINITY
} else {
- (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
+ (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
}
}
@@ -1443,6 +1443,8 @@ mod tests {
// issue 63271
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
+ // regression test for the catastrophic cancellation fixed in 72486
+ assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
}
#[test]
From 591584e71f7d8a613d586066c8b01c1eecf08f35 Mon Sep 17 00:00:00 2001
From: Mikail Bagishov
Date: Tue, 26 May 2020 23:48:36 +0300
Subject: [PATCH 007/123] Add tests for 'impl Default for [T; N]'
---
src/libcore/tests/array.rs | 41 ++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs
index c2a816f0a7d90..41855a9a8cbab 100644
--- a/src/libcore/tests/array.rs
+++ b/src/libcore/tests/array.rs
@@ -241,3 +241,44 @@ fn iterator_drops() {
}
assert_eq!(i.get(), 5);
}
+
+#[test]
+fn array_default_impl_avoids_leaks_on_panic() {
+ use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+ static COUNTER: AtomicUsize = AtomicUsize::new(0);
+ #[derive(Debug)]
+ struct Bomb(usize);
+
+ impl Default for Bomb {
+ fn default() -> Bomb {
+ if COUNTER.load(Relaxed) == 3 {
+ panic!("bomb limit exceeded");
+ }
+
+ COUNTER.fetch_add(1, Relaxed);
+ Bomb(COUNTER.load(Relaxed))
+ }
+ }
+
+ impl Drop for Bomb {
+ fn drop(&mut self) {
+ COUNTER.fetch_sub(1, Relaxed);
+ }
+ }
+
+ let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default());
+ let panic_msg = match res {
+ Ok(_) => unreachable!(),
+ Err(p) => p.downcast::<&'static str>().unwrap(),
+ };
+ assert_eq!(*panic_msg, "bomb limit exceeded");
+ // check that all bombs are successfully dropped
+ assert_eq!(COUNTER.load(Relaxed), 0);
+}
+
+#[test]
+fn empty_array_is_always_default() {
+ struct DoesNotImplDefault;
+
+ let _arr = <[DoesNotImplDefault; 0]>::default();
+}
From 3313bf62ac45fab2c39e49c788423153754087a9 Mon Sep 17 00:00:00 2001
From: Mikail Bagishov
Date: Thu, 28 May 2020 20:45:21 +0300
Subject: [PATCH 008/123] Skip leak test on targets without panic=unwind
---
src/libcore/tests/array.rs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs
index 41855a9a8cbab..4bc44e98fc802 100644
--- a/src/libcore/tests/array.rs
+++ b/src/libcore/tests/array.rs
@@ -242,7 +242,14 @@ fn iterator_drops() {
assert_eq!(i.get(), 5);
}
+// This test does not work on targets without panic=unwind support.
+// To work around this problem, test is marked is should_panic, so it will
+// be automagically skipped on unsuitable targets, such as
+// wasm32-unknown-unkown.
+//
+// It means that we use panic for indicating success.
#[test]
+#[should_panic(expected = "test succeeded")]
fn array_default_impl_avoids_leaks_on_panic() {
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
static COUNTER: AtomicUsize = AtomicUsize::new(0);
@@ -274,6 +281,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
assert_eq!(*panic_msg, "bomb limit exceeded");
// check that all bombs are successfully dropped
assert_eq!(COUNTER.load(Relaxed), 0);
+ panic!("test succeeded")
}
#[test]
From f7d745f33d950c050e0a5a2ee2ee9f0e1269e956 Mon Sep 17 00:00:00 2001
From: Ralf Jung
Date: Sat, 23 May 2020 13:22:45 +0200
Subject: [PATCH 009/123] tag/niche terminology cleanup
---
.../debuginfo/metadata.rs | 105 +++++++++---------
src/librustc_codegen_ssa/mir/place.rs | 44 ++++----
src/librustc_lint/types.rs | 14 +--
src/librustc_middle/ty/layout.rs | 58 +++++-----
src/librustc_mir/interpret/operand.rs | 27 ++---
src/librustc_mir/interpret/place.rs | 41 +++----
src/librustc_mir/interpret/step.rs | 4 +-
src/librustc_mir/interpret/validity.rs | 4 +-
src/librustc_target/abi/mod.rs | 27 +++--
src/test/ui/layout/debug.stderr | 12 +-
10 files changed, 167 insertions(+), 169 deletions(-)
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 0cce0b25e5893..01f630a31a18b 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -1,4 +1,4 @@
-use self::EnumDiscriminantInfo::*;
+use self::EnumTagInfo::*;
use self::MemberDescriptionFactory::*;
use self::RecursiveTypeDescription::*;
@@ -40,7 +40,7 @@ use rustc_middle::{bug, span_bug};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::{Interner, Symbol};
use rustc_span::{self, SourceFile, SourceFileHash, Span};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
+use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
@@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names(
struct EnumMemberDescriptionFactory<'ll, 'tcx> {
enum_type: Ty<'tcx>,
layout: TyAndLayout<'tcx>,
- discriminant_type_metadata: Option<&'ll DIType>,
+ tag_type_metadata: Option<&'ll DIType>,
containing_scope: &'ll DIScope,
span: Span,
}
@@ -1385,7 +1385,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
self.layout,
variant_info,
- NoDiscriminant,
+ NoTag,
self_metadata,
self.span,
);
@@ -1409,19 +1409,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
}]
}
Variants::Multiple {
- discr_kind: DiscriminantKind::Tag,
- discr_index,
+ tag_encoding: TagEncoding::Direct,
+ tag_field,
ref variants,
..
} => {
- let discriminant_info = if fallback {
- RegularDiscriminant {
- discr_field: Field::from(discr_index),
- discr_type_metadata: self.discriminant_type_metadata.unwrap(),
+ let tag_info = if fallback {
+ RegularTag {
+ tag_field: Field::from(tag_field),
+ tag_type_metadata: self.tag_type_metadata.unwrap(),
}
} else {
// This doesn't matter in this case.
- NoDiscriminant
+ NoTag
};
variants
.iter_enumerated()
@@ -1432,7 +1432,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
variant,
variant_info,
- discriminant_info,
+ tag_info,
self_metadata,
self.span,
);
@@ -1467,11 +1467,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
.collect()
}
Variants::Multiple {
- discr_kind:
- DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant },
- ref discr,
+ tag_encoding:
+ TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
+ ref tag,
ref variants,
- discr_index,
+ tag_field,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
@@ -1480,7 +1480,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
variant,
variant_info_for(dataful_variant),
- OptimizedDiscriminant,
+ OptimizedTag,
self.containing_scope,
self.span,
);
@@ -1524,8 +1524,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
&mut name,
self.layout,
- self.layout.fields.offset(discr_index),
- self.layout.field(cx, discr_index).size,
+ self.layout.fields.offset(tag_field),
+ self.layout.field(cx, tag_field).size,
);
variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
name.push_str(variant_name);
@@ -1552,7 +1552,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
cx,
variant,
variant_info,
- OptimizedDiscriminant,
+ OptimizedTag,
self_metadata,
self.span,
);
@@ -1573,7 +1573,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
let value = (i.as_u32() as u128)
.wrapping_sub(niche_variants.start().as_u32() as u128)
.wrapping_add(niche_start);
- let value = truncate(value, discr.value.size(cx));
+ let value = truncate(value, tag.value.size(cx));
// NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected.
@@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> {
/// Cloned from the `layout::Struct` describing the variant.
offsets: Vec,
args: Vec<(String, Ty<'tcx>)>,
- discriminant_type_metadata: Option<&'ll DIType>,
+ tag_type_metadata: Option<&'ll DIType>,
span: Span,
}
@@ -1617,7 +1617,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
MemberDescription {
name: name.to_string(),
type_metadata: if use_enum_fallback(cx) {
- match self.discriminant_type_metadata {
+ match self.tag_type_metadata {
// Discriminant is always the first field of our variant
// when using the enum fallback.
Some(metadata) if i == 0 => metadata,
@@ -1638,10 +1638,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
}
#[derive(Copy, Clone)]
-enum EnumDiscriminantInfo<'ll> {
- RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType },
- OptimizedDiscriminant,
- NoDiscriminant,
+enum EnumTagInfo<'ll> {
+ RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+ OptimizedTag,
+ NoTag,
}
#[derive(Copy, Clone)]
@@ -1706,7 +1706,7 @@ fn describe_enum_variant(
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
- discriminant_info: EnumDiscriminantInfo<'ll>,
+ discriminant_info: EnumTagInfo<'ll>,
containing_scope: &'ll DIScope,
span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
@@ -1722,12 +1722,12 @@ fn describe_enum_variant(
let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
- RegularDiscriminant { discr_field, .. } => {
+ RegularTag { tag_field, .. } => {
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
- let offset = enum_layout.fields.offset(discr_field.as_usize());
+ let offset = enum_layout.fields.offset(tag_field.as_usize());
let args =
- ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty);
+ ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
(Some(offset), Some(args))
}
_ => (None, None),
@@ -1757,8 +1757,8 @@ fn describe_enum_variant(
let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
offsets,
args,
- discriminant_type_metadata: match discriminant_info {
- RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata),
+ tag_type_metadata: match discriminant_info {
+ RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
_ => None,
},
span,
@@ -1880,18 +1880,18 @@ fn prepare_enum_metadata(
if let (
&Abi::Scalar(_),
- &Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. },
+ &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
) = (&layout.abi, &layout.variants)
{
- return FinalMetadata(discriminant_type_metadata(discr.value));
+ return FinalMetadata(discriminant_type_metadata(tag.value));
}
if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants {
Variants::Single { .. }
- | Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None,
- Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => {
- Some(discriminant_type_metadata(discr.value))
+ | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+ Some(discriminant_type_metadata(tag.value))
}
};
@@ -1927,7 +1927,7 @@ fn prepare_enum_metadata(
EnumMDF(EnumMemberDescriptionFactory {
enum_type,
layout,
- discriminant_type_metadata,
+ tag_type_metadata: discriminant_type_metadata,
containing_scope,
span,
}),
@@ -1943,16 +1943,13 @@ fn prepare_enum_metadata(
Variants::Single { .. } => None,
Variants::Multiple {
- discr_kind: DiscriminantKind::Niche { .. },
- ref discr,
- discr_index,
- ..
+ tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
} => {
// Find the integer type of the correct size.
- let size = discr.value.size(cx);
- let align = discr.value.align(cx);
+ let size = tag.value.size(cx);
+ let align = tag.value.align(cx);
- let discr_type = match discr.value {
+ let tag_type = match tag.value {
Int(t, _) => t,
F32 => Integer::I32,
F64 => Integer::I64,
@@ -1960,7 +1957,7 @@ fn prepare_enum_metadata(
}
.to_ty(cx.tcx, false);
- let discr_metadata = basic_type_metadata(cx, discr_type);
+ let tag_metadata = basic_type_metadata(cx, tag_type);
unsafe {
Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
@@ -1971,17 +1968,15 @@ fn prepare_enum_metadata(
UNKNOWN_LINE_NUMBER,
size.bits(),
align.abi.bits() as u32,
- layout.fields.offset(discr_index).bits(),
+ layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial,
- discr_metadata,
+ tag_metadata,
))
}
}
- Variants::Multiple {
- discr_kind: DiscriminantKind::Tag, ref discr, discr_index, ..
- } => {
- let discr_type = discr.value.to_ty(cx.tcx);
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
+ let discr_type = tag.value.to_ty(cx.tcx);
let (size, align) = cx.size_and_align_of(discr_type);
let discr_metadata = basic_type_metadata(cx, discr_type);
@@ -1995,7 +1990,7 @@ fn prepare_enum_metadata(
UNKNOWN_LINE_NUMBER,
size.bits(),
align.bits() as u32,
- layout.fields.offset(discr_index).bits(),
+ layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial,
discr_metadata,
))
@@ -2081,7 +2076,7 @@ fn prepare_enum_metadata(
EnumMDF(EnumMemberDescriptionFactory {
enum_type,
layout,
- discriminant_type_metadata: None,
+ tag_type_metadata: None,
containing_scope,
span,
}),
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 2be0679382900..0c8638b673d4f 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int};
+use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
#[derive(Copy, Clone, Debug)]
@@ -199,7 +199,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
if self.layout.abi.is_uninhabited() {
return bx.cx().const_undef(cast_to);
}
- let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
+ let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
Variants::Single { index } => {
let discr_val = self
.layout
@@ -208,33 +208,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
.map_or(index.as_u32() as u128, |discr| discr.val);
return bx.cx().const_uint_big(cast_to, discr_val);
}
- Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
- (discr, discr_kind, discr_index)
+ Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+ (tag, tag_encoding, tag_field)
}
};
// Read the tag/niche-encoded discriminant from memory.
- let encoded_discr = self.project_field(bx, discr_index);
- let encoded_discr = bx.load_operand(encoded_discr);
+ let tag = self.project_field(bx, tag_field);
+ let tag = bx.load_operand(tag);
// Decode the discriminant (specifically if it's niche-encoded).
- match *discr_kind {
- DiscriminantKind::Tag => {
- let signed = match discr_scalar.value {
+ match *tag_encoding {
+ TagEncoding::Direct => {
+ let signed = match tag_scalar.value {
// We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because
// then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
- Int(_, signed) => !discr_scalar.is_bool() && signed,
+ Int(_, signed) => !tag_scalar.is_bool() && signed,
_ => false,
};
- bx.intcast(encoded_discr.immediate(), cast_to, signed)
+ bx.intcast(tag.immediate(), cast_to, signed)
}
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Rebase from niche values to discriminants, and check
// whether the result is in range for the niche variants.
- let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout);
- let encoded_discr = encoded_discr.immediate();
+ let niche_llty = bx.cx().immediate_backend_type(tag.layout);
+ let tag = tag.immediate();
// We first compute the "relative discriminant" (wrt `niche_variants`),
// that is, if `n = niche_variants.end() - niche_variants.start()`,
@@ -248,9 +248,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
let relative_discr = if niche_start == 0 {
// Avoid subtracting `0`, which wouldn't work for pointers.
// FIXME(eddyb) check the actual primitive type here.
- encoded_discr
+ tag
} else {
- bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start))
+ bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
};
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
let is_niche = {
@@ -312,8 +312,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
Variants::Single { index } => {
assert_eq!(index, variant_index);
}
- Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => {
- let ptr = self.project_field(bx, discr_index);
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
+ let ptr = self.project_field(bx, tag_field);
let to =
self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
bx.store(
@@ -323,9 +323,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
);
}
Variants::Multiple {
- discr_kind:
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
- discr_index,
+ tag_encoding:
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+ tag_field,
..
} => {
if variant_index != dataful_variant {
@@ -339,7 +339,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
}
- let niche = self.project_field(bx, discr_index);
+ let niche = self.project_field(bx, tag_field);
let niche_llty = bx.cx().immediate_backend_type(niche.layout);
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
let niche_value = (niche_value as u128).wrapping_add(niche_start);
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 703c2a7a443a9..6f4e2c69e339f 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -16,7 +16,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc_span::source_map;
use rustc_span::symbol::sym;
use rustc_span::Span;
-use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
use rustc_target::spec::abi::Abi;
use log::debug;
@@ -1036,15 +1036,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
};
let (variants, tag) = match layout.variants {
Variants::Multiple {
- discr_kind: DiscriminantKind::Tag,
- ref discr,
+ tag_encoding: TagEncoding::Direct,
+ ref tag,
ref variants,
..
- } => (variants, discr),
+ } => (variants, tag),
_ => return,
};
- let discr_size = tag.value.size(&cx.tcx).bytes();
+ let tag_size = tag.value.size(&cx.tcx).bytes();
debug!(
"enum `{}` is {} bytes large with layout:\n{:#?}",
@@ -1058,8 +1058,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
.iter()
.zip(variants)
.map(|(variant, variant_layout)| {
- // Subtract the size of the enum discriminant.
- let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
+ // Subtract the size of the enum tag.
+ let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
bytes
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 5566e187c0c5c..fde2627e29dcb 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -975,13 +975,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
return Ok(tcx.intern_layout(Layout {
variants: Variants::Multiple {
- discr: niche_scalar,
- discr_kind: DiscriminantKind::Niche {
+ tag: niche_scalar,
+ tag_encoding: TagEncoding::Niche {
dataful_variant: i,
niche_variants,
niche_start,
},
- discr_index: 0,
+ tag_field: 0,
variants: st,
},
fields: FieldsShape::Arbitrary {
@@ -1217,9 +1217,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
tcx.intern_layout(Layout {
variants: Variants::Multiple {
- discr: tag,
- discr_kind: DiscriminantKind::Tag,
- discr_index: 0,
+ tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: 0,
variants: layout_variants,
},
fields: FieldsShape::Arbitrary {
@@ -1400,15 +1400,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Build a prefix layout, including "promoting" all ineligible
// locals as part of the prefix. We compute the layout of all of
// these fields at once to get optimal packing.
- let discr_index = substs.as_generator().prefix_tys().count();
+ let tag_index = substs.as_generator().prefix_tys().count();
// `info.variant_fields` already accounts for the reserved variants, so no need to add them.
let max_discr = (info.variant_fields.len() - 1) as u128;
let discr_int = Integer::fit_unsigned(max_discr);
let discr_int_ty = discr_int.to_ty(tcx, false);
- let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
- let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone()));
- let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout };
+ let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
+ let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
+ let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
let promoted_layouts = ineligible_locals
.iter()
@@ -1419,7 +1419,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
.as_generator()
.prefix_tys()
.map(|ty| self.layout_of(ty))
- .chain(iter::once(Ok(discr_layout)))
+ .chain(iter::once(Ok(tag_layout)))
.chain(promoted_layouts)
.collect::, _>>()?;
let prefix = self.univariant_uninterned(
@@ -1442,7 +1442,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
// "outer" and "promoted" fields respectively.
- let b_start = (discr_index + 1) as u32;
+ let b_start = (tag_index + 1) as u32;
let offsets_b = offsets.split_off(b_start as usize);
let offsets_a = offsets;
@@ -1559,9 +1559,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let layout = tcx.intern_layout(Layout {
variants: Variants::Multiple {
- discr,
- discr_kind: DiscriminantKind::Tag,
- discr_index,
+ tag: tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: tag_index,
variants,
},
fields: outer_fields,
@@ -1681,7 +1681,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}
- Variants::Multiple { ref discr, ref discr_kind, .. } => {
+ Variants::Multiple { ref tag, ref tag_encoding, .. } => {
debug!(
"print-type-size `{:#?}` adt general variants def {}",
layout.ty,
@@ -1703,8 +1703,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
record(
adt_kind.into(),
adt_packed,
- match discr_kind {
- DiscriminantKind::Tag => Some(discr.value.size(self)),
+ match tag_encoding {
+ TagEncoding::Direct => Some(tag.value.size(self)),
_ => None,
},
variant_infos,
@@ -2029,11 +2029,11 @@ where
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
let tcx = cx.tcx();
- let discr_layout = |discr: &Scalar| -> C::TyAndLayout {
- let layout = Layout::scalar(cx, discr.clone());
+ let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
+ let layout = Layout::scalar(cx, tag.clone());
MaybeResult::from(Ok(TyAndLayout {
layout: tcx.intern_layout(layout),
- ty: discr.value.to_ty(tcx),
+ ty: tag.value.to_ty(tcx),
}))
};
@@ -2110,9 +2110,9 @@ where
.unwrap()
.nth(i)
.unwrap(),
- Variants::Multiple { ref discr, discr_index, .. } => {
- if i == discr_index {
- return discr_layout(discr);
+ Variants::Multiple { ref tag, tag_field, .. } => {
+ if i == tag_field {
+ return tag_layout(tag);
}
substs.as_generator().prefix_tys().nth(i).unwrap()
}
@@ -2129,9 +2129,9 @@ where
Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
// Discriminant field for enums (where applicable).
- Variants::Multiple { ref discr, .. } => {
+ Variants::Multiple { ref tag, .. } => {
assert_eq!(i, 0);
- return discr_layout(discr);
+ return tag_layout(tag);
}
}
}
@@ -2208,10 +2208,10 @@ where
// using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers).
Variants::Multiple {
- discr_kind: DiscriminantKind::Niche { dataful_variant, .. },
- discr_index,
+ tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+ tag_field,
..
- } if this.fields.offset(discr_index) == offset => {
+ } if this.fields.offset(tag_field) == offset => {
Some(this.for_variant(cx, dataful_variant))
}
_ => Some(this),
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index db4473154c471..7da50eaa3e392 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
use rustc_middle::ty::Ty;
use rustc_middle::{mir, ty};
-use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
+use rustc_target::abi::{Abi, TagEncoding, HasDataLayout, LayoutOf, Size};
use rustc_target::abi::{VariantIdx, Variants};
use super::{
@@ -587,7 +587,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
op: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar, VariantIdx)> {
trace!("read_discriminant_value {:#?}", op.layout);
-
// Get type and layout of the discriminant.
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
trace!("discriminant type: {:?}", discr_layout.ty);
@@ -596,10 +595,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// This is not to be confused with its "variant index", which is just determining its position in the
// declared list of variants -- they can differ with explicitly assigned discriminants.
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
- // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
- // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
- // rather confusing.
- let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
+ // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
+ let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
Variants::Single { index } => {
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
Some(discr) => {
@@ -615,8 +612,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
return Ok((discr, index));
}
- Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
- (discr, discr_kind, discr_index)
+ Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+ (tag, tag_encoding, tag_field)
}
};
@@ -633,21 +630,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
// Read tag and sanity-check `tag_layout`.
- let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
+ let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
let tag_val = tag_val.to_scalar()?;
trace!("tag value: {:?}", tag_val);
// Figure out which discriminant and variant this corresponds to.
- Ok(match *tag_kind {
- DiscriminantKind::Tag => {
+ Ok(match *tag_encoding {
+ TagEncoding::Direct => {
let tag_bits = self
.force_bits(tag_val, tag_layout.size)
.map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
// Cast bits from tag layout to discriminant layout.
- let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
- let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
+ let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+ let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants.
let index = match op.layout.ty.kind {
ty::Adt(adt, _) => {
@@ -663,9 +660,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
.ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
// Return the cast value, and the index.
- (discr_val_cast, index.0)
+ (discr_val, index.0)
}
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Compute the variant this niche value/"tag" corresponds to. With niche layout,
// discriminant (encoded in niche/tag) and variant index are the same.
let variants_start = niche_variants.start().as_u32();
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 3f0800b12b549..1e6335c871e7c 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -9,7 +9,7 @@ use rustc_macros::HashStable;
use rustc_middle::mir;
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape};
+use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{
@@ -1031,7 +1031,8 @@ where
MPlaceTy { mplace, layout }
}
- pub fn write_discriminant_index(
+ /// Writes the discriminant of the given variant.
+ pub fn write_discriminant(
&mut self,
variant_index: VariantIdx,
dest: PlaceTy<'tcx, M::PointerTag>,
@@ -1047,9 +1048,9 @@ where
assert_eq!(index, variant_index);
}
Variants::Multiple {
- discr_kind: DiscriminantKind::Tag,
- discr: ref discr_layout,
- discr_index,
+ tag_encoding: TagEncoding::Direct,
+ tag: ref tag_layout,
+ tag_field,
..
} => {
// No need to validate that the discriminant here because the
@@ -1061,17 +1062,17 @@ where
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
- let size = discr_layout.value.size(self);
- let discr_val = truncate(discr_val, size);
+ let size = tag_layout.value.size(self);
+ let tag_val = truncate(discr_val, size);
- let discr_dest = self.place_field(dest, discr_index)?;
- self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
+ let tag_dest = self.place_field(dest, tag_field)?;
+ self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
}
Variants::Multiple {
- discr_kind:
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
- discr: ref discr_layout,
- discr_index,
+ tag_encoding:
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+ tag: ref tag_layout,
+ tag_field,
..
} => {
// No need to validate that the discriminant here because the
@@ -1084,19 +1085,19 @@ where
.checked_sub(variants_start)
.expect("overflow computing relative variant idx");
// We need to use machine arithmetic when taking into account `niche_start`:
- // discr_val = variant_index_relative + niche_start_val
- let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
- let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
+ // tag_val = variant_index_relative + niche_start_val
+ let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
+ let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
let variant_index_relative_val =
- ImmTy::from_uint(variant_index_relative, discr_layout);
- let discr_val = self.binary_op(
+ ImmTy::from_uint(variant_index_relative, tag_layout);
+ let tag_val = self.binary_op(
mir::BinOp::Add,
variant_index_relative_val,
niche_start_val,
)?;
// Write result.
- let niche_dest = self.place_field(dest, discr_index)?;
- self.write_immediate(*discr_val, niche_dest)?;
+ let niche_dest = self.place_field(dest, tag_field)?;
+ self.write_immediate(*tag_val, niche_dest)?;
}
}
}
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index bd4df788057e2..029b83492d593 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -89,7 +89,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?;
- self.write_discriminant_index(*variant_index, dest)?;
+ self.write_discriminant(*variant_index, dest)?;
}
// Mark locals as alive
@@ -174,7 +174,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Aggregate(ref kind, ref operands) => {
let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
- self.write_discriminant_index(variant_index, dest)?;
+ self.write_discriminant(variant_index, dest)?;
if adt_def.is_enum() {
(self.place_downcast(dest, variant_index)?, active_field_index)
} else {
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index e962dfb2b3e86..f21a96a979092 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
// First, check if we are projecting to a variant.
match layout.variants {
- Variants::Multiple { discr_index, .. } => {
- if discr_index == field {
+ Variants::Multiple { tag_field, .. } => {
+ if tag_field == field {
return match layout.ty.kind {
ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
ty::Generator(..) => PathElem::GeneratorTag,
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index dcf181cb59f4a..c79e9bb289008 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -809,25 +809,30 @@ pub enum Variants {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },
- /// Enum-likes with more than one inhabited variant: for each case there is
- /// a struct, and they all have space reserved for the discriminant.
- /// For enums this is the sole field of the layout.
+ /// Enum-likes with more than one inhabited variant: each variant comes with
+ /// a *discriminant* (usually the same as the variant index but the user can
+ /// assign explicit discriminant values). That discriminant is encoded
+ /// as a *tag* on the machine. The layout of each variant is
+ /// a struct, and they all have space reserved for the tag.
+ /// For enums, the tag is the sole field of the layout.
Multiple {
- discr: Scalar,
- discr_kind: DiscriminantKind,
- discr_index: usize,
+ tag: Scalar,
+ tag_encoding: TagEncoding,
+ tag_field: usize,
variants: IndexVec,
},
}
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum DiscriminantKind {
- /// Integer tag holding the discriminant value itself.
- Tag,
+pub enum TagEncoding {
+ /// The tag directly stores the discriminant, but possibly with a smaller layout
+ /// (so converting the tag to the discriminant can require sign extension).
+ Direct,
/// Niche (values invalid for a type) encoding the discriminant:
- /// the variant `dataful_variant` contains a niche at an arbitrary
- /// offset (field `discr_index` of the enum), which for a variant with
+ /// Discriminant and variant index coincide.
+ /// The variant `dataful_variant` contains a niche at an arbitrary
+ /// offset (field `tag_field` of the enum), which for a variant with
/// discriminant `d` is set to
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
///
diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr
index cd8ebdffb730b..1a371c6b17000 100644
--- a/src/test/ui/layout/debug.stderr
+++ b/src/test/ui/layout/debug.stderr
@@ -10,15 +10,15 @@ error: layout_of(E) = Layout {
],
},
variants: Multiple {
- discr: Scalar {
+ tag: Scalar {
value: Int(
I32,
false,
),
valid_range: 0..=0,
},
- discr_kind: Tag,
- discr_index: 0,
+ tag_encoding: Direct,
+ tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
@@ -202,15 +202,15 @@ error: layout_of(std::result::Result) = Layout {
],
},
variants: Multiple {
- discr: Scalar {
+ tag: Scalar {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
- discr_kind: Tag,
- discr_index: 0,
+ tag_encoding: Direct,
+ tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
From 7a6d03c2699787644b44f7bc3e8252d1508880b8 Mon Sep 17 00:00:00 2001
From: Ralf Jung
Date: Sat, 30 May 2020 14:21:56 +0200
Subject: [PATCH 010/123] miri errors: rename InvalidDiscriminant -> InvalidTag
---
src/librustc_middle/mir/interpret/error.rs | 6 +++---
src/librustc_mir/interpret/operand.rs | 8 ++++----
src/librustc_mir/interpret/validity.rs | 4 ++--
src/test/ui/consts/const-eval/double_check2.stderr | 2 +-
src/test/ui/consts/const-eval/ub-enum.stderr | 4 ++--
5 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs
index fc588e049d7d8..6646aad6fc740 100644
--- a/src/librustc_middle/mir/interpret/error.rs
+++ b/src/librustc_middle/mir/interpret/error.rs
@@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
InvalidBool(u8),
/// Using a non-character `u32` as character.
InvalidChar(u32),
- /// An enum discriminant was set to a value which was outside the range of valid values.
- InvalidDiscriminant(Scalar),
+ /// The tag of an enum does not encode an actual discriminant.
+ InvalidTag(Scalar),
/// Using a pointer-not-to-a-function as function pointer.
InvalidFunctionPointer(Pointer),
/// Using a string that is not valid UTF-8,
@@ -463,7 +463,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
InvalidChar(c) => {
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
}
- InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val),
+ InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
InvalidFunctionPointer(p) => {
write!(f, "using {} as function pointer but it does not point to a function", p)
}
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 7da50eaa3e392..fb08e83b76942 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
use rustc_middle::ty::Ty;
use rustc_middle::{mir, ty};
-use rustc_target::abi::{Abi, TagEncoding, HasDataLayout, LayoutOf, Size};
+use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
use super::{
@@ -641,7 +641,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
TagEncoding::Direct => {
let tag_bits = self
.force_bits(tag_val, tag_layout.size)
- .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+ .map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?;
// Cast bits from tag layout to discriminant layout.
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
let discr_bits = discr_val.assert_bits(discr_layout.size);
@@ -658,7 +658,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
_ => bug!("tagged layout for non-adt non-generator"),
}
- .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+ .ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?;
// Return the cast value, and the index.
(discr_val, index.0)
}
@@ -674,7 +674,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&& variants_start == variants_end
&& !self.memory.ptr_may_be_null(ptr);
if !ptr_valid {
- throw_ub!(InvalidDiscriminant(tag_val.erase_tag()))
+ throw_ub!(InvalidTag(tag_val.erase_tag()))
}
dataful_variant
}
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index f21a96a979092..8dea811d8bcd4 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -696,8 +696,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
try_validation!(
self.walk_value(op),
self.path,
- err_ub!(InvalidDiscriminant(val)) =>
- { "{}", val } expected { "a valid enum discriminant" },
+ err_ub!(InvalidTag(val)) =>
+ { "{}", val } expected { "a valid enum tag" },
err_unsup!(ReadPointerAsBytes) =>
{ "a pointer" } expected { "plain (non-pointer) bytes" },
);
diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr
index 81fa5c0df13f6..93dd9a53ec99f 100644
--- a/src/test/ui/consts/const-eval/double_check2.stderr
+++ b/src/test/ui/consts/const-eval/double_check2.stderr
@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {(
LL | | Union { u8: &BAR }.foo,
LL | | Union { u8: &BAR }.bar,
LL | | )};
- | |___^ type validation failed: encountered 0x05 at .1., but expected a valid enum discriminant
+ | |___^ type validation failed: encountered 0x05 at .1., but expected a valid enum tag
|
= 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/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr
index d8dafac3e70a1..d40073fb18fb0 100644
--- a/src/test/ui/consts/const-eval/ub-enum.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.stderr
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:24:1
|
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum discriminant
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag
|
= 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.
@@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:42:1
|
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum discriminant
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag
|
= 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 d1c275b350f9ae74be92114f4819d6afb55d6007 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov
Date: Sat, 30 May 2020 18:46:52 +0300
Subject: [PATCH 011/123] linker: MSVC supports linking static libraries as a
whole archive
---
src/librustc_codegen_ssa/back/linker.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 46c365efdb5fa..511c851fd31ab 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -704,12 +704,14 @@ impl<'a> Linker for MsvcLinker<'a> {
}
fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
- // not supported?
self.link_staticlib(lib);
+ self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
}
fn link_whole_rlib(&mut self, path: &Path) {
- // not supported?
self.link_rlib(path);
+ let mut arg = OsString::from("/WHOLEARCHIVE:");
+ arg.push(path);
+ self.cmd.arg(arg);
}
fn optimize(&mut self) {
// Needs more investigation of `/OPT` arguments
From 1bc4e45b3fe3a0817908bd7cc21ec23798d38d63 Mon Sep 17 00:00:00 2001
From: "Carol (Nichols || Goulding)"
Date: Mon, 1 Jun 2020 22:18:38 -0400
Subject: [PATCH 012/123] Only highlight results via mouseover if mouse has
moved
---
src/librustdoc/html/static/main.js | 37 +++++++++++++++++++-----------
1 file changed, 24 insertions(+), 13 deletions(-)
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index ac5a2f96b26c6..fc31f6c760675 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -100,6 +100,8 @@ function defocusSearchBar() {
// 2 for "In Return Types"
var currentTab = 0;
+ var mouseMovedAfterSearch = true;
+
var titleBeforeSearch = document.title;
function clearInputTimeout() {
@@ -162,6 +164,7 @@ function defocusSearchBar() {
}
addClass(main, "hidden");
removeClass(search, "hidden");
+ mouseMovedAfterSearch = false;
}
function hideSearchResults(search) {
@@ -424,6 +427,12 @@ function defocusSearchBar() {
document.addEventListener("keypress", handleShortcut);
document.addEventListener("keydown", handleShortcut);
+ function resetMouseMoved(ev) {
+ mouseMovedAfterSearch = true;
+ }
+
+ document.addEventListener("mousemove", resetMouseMoved);
+
var handleSourceHighlight = (function() {
var prev_line_id = 0;
@@ -1353,20 +1362,22 @@ function defocusSearchBar() {
}
};
var mouseover_func = function(e) {
- var el = e.target;
- // to retrieve the real "owner" of the event.
- while (el.tagName !== "TR") {
- el = el.parentNode;
- }
- clearTimeout(hoverTimeout);
- hoverTimeout = setTimeout(function() {
- onEachLazy(document.getElementsByClassName("search-results"), function(e) {
- onEachLazy(e.getElementsByClassName("result"), function(i_e) {
- removeClass(i_e, "highlighted");
+ if (mouseMovedAfterSearch) {
+ var el = e.target;
+ // to retrieve the real "owner" of the event.
+ while (el.tagName !== "TR") {
+ el = el.parentNode;
+ }
+ clearTimeout(hoverTimeout);
+ hoverTimeout = setTimeout(function() {
+ onEachLazy(document.getElementsByClassName("search-results"), function(e) {
+ onEachLazy(e.getElementsByClassName("result"), function(i_e) {
+ removeClass(i_e, "highlighted");
+ });
});
- });
- addClass(el, "highlighted");
- }, 20);
+ addClass(el, "highlighted");
+ }, 20);
+ }
};
onEachLazy(document.getElementsByClassName("search-results"), function(e) {
onEachLazy(e.getElementsByClassName("result"), function(i_e) {
From 20abc70e04eefa252e5a8bfe934cb54c51c1da37 Mon Sep 17 00:00:00 2001
From: Oliver Scherer
Date: Wed, 3 Jun 2020 13:45:56 +0200
Subject: [PATCH 013/123] Don't intern memory in const prop.
This isn't sound without validation. We don't want to report errors in case of failure to intern and validate, we just don't want to const prop. Interning and const prop is not built for this, let's not do it until we have a clearer picture on aggregate propagation.
---
src/librustc_mir/interpret/intern.rs | 12 ++++++------
src/librustc_mir/transform/const_prop.rs | 12 ++++--------
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 02a7f24a1e351..4c1cf1b56ae66 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -294,7 +294,6 @@ pub enum InternKind {
Static(hir::Mutability),
Constant,
Promoted,
- ConstProp,
}
/// Intern `ret` and everything it references.
@@ -315,9 +314,7 @@ pub fn intern_const_alloc_recursive>(
let base_intern_mode = match intern_kind {
InternKind::Static(mutbl) => InternMode::Static(mutbl),
// FIXME: what about array lengths, array initializers?
- InternKind::Constant | InternKind::ConstProp | InternKind::Promoted => {
- InternMode::ConstBase
- }
+ InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
};
// Type based interning.
@@ -359,7 +356,10 @@ pub fn intern_const_alloc_recursive>(
Err(error) => {
ecx.tcx.sess.delay_span_bug(
ecx.tcx.span,
- "error during interning should later cause validation failure",
+ &format!(
+ "error during interning should later cause validation failure: {}",
+ error
+ ),
);
// Some errors shouldn't come up because creating them causes
// an allocation, which we should avoid. When that happens,
@@ -400,7 +400,7 @@ pub fn intern_const_alloc_recursive>(
// immutability is so important.
alloc.mutability = Mutability::Not;
}
- InternKind::Constant | InternKind::ConstProp => {
+ InternKind::Constant => {
// If it's a constant, we should not have any "leftovers" as everything
// is tracked by const-checking.
// FIXME: downgrade this to a warning? It rejects some legitimate consts,
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 92000e6411354..97e5b8bc047f0 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -27,9 +27,9 @@ use rustc_trait_selection::traits;
use crate::const_eval::error_to_const_error;
use crate::interpret::{
- self, compile_time_machine, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy,
- Immediate, InternKind, InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy,
- Operand as InterpOperand, PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup,
+ self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState,
+ LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
+ ScalarMaybeUninit, StackPopCleanup,
};
use crate::transform::{MirPass, MirSource};
@@ -707,11 +707,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
ScalarMaybeUninit::Scalar(l),
ScalarMaybeUninit::Scalar(r),
)) => l.is_bits() && r.is_bits(),
- interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
- let mplace = op.assert_mem_place(&self.ecx);
- intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false);
- true
- }
+ interpret::Operand::Indirect(_) if mir_opt_level >= 2 => true,
_ => false,
}
}
From 1e88f130a347f8b223031eafe75c0772ccfec00c Mon Sep 17 00:00:00 2001
From: Wesley Wiser
Date: Mon, 8 Jun 2020 08:14:45 -0400
Subject: [PATCH 014/123] Stop allowing `Indirect(..)` values to be propagated
Closes #72679
Closes #72372
Closes #72285
---
src/librustc_mir/transform/const_prop.rs | 1 -
src/test/mir-opt/const_prop/discriminant.rs | 5 ++
.../32bit/rustc.main.ConstProp.diff | 75 +++++++++----------
.../64bit/rustc.main.ConstProp.diff | 75 +++++++++----------
4 files changed, 73 insertions(+), 83 deletions(-)
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 97e5b8bc047f0..39548d8a535f7 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -707,7 +707,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
ScalarMaybeUninit::Scalar(l),
ScalarMaybeUninit::Scalar(r),
)) => l.is_bits() && r.is_bits(),
- interpret::Operand::Indirect(_) if mir_opt_level >= 2 => true,
_ => false,
}
}
diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs
index 04541b94ad780..13e8eb3e44e1a 100644
--- a/src/test/mir-opt/const_prop/discriminant.rs
+++ b/src/test/mir-opt/const_prop/discriminant.rs
@@ -1,5 +1,10 @@
// compile-flags: -O
+// FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
+// `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect`
+// and `InterpCx::eval_place()` always forces an allocation which creates the `Indirect`.
+// Fixing either of those will allow us to const-prop this away.
+
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR rustc.main.ConstProp.diff
fn main() {
diff --git a/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff
index 9979ea9549891..1c873f53f378a 100644
--- a/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff
@@ -2,100 +2,93 @@
+ // MIR for `main` after ConstProp
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11
- let _1: i32; // in scope 0 at $DIR/discriminant.rs:6:9: 6:10
- let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:6:13: 6:64
- let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44
- let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:6:21: 6:31
+ let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11
+ let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44
+ let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31
scope 1 {
- debug x => _1; // in scope 1 at $DIR/discriminant.rs:6:9: 6:10
+ debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/discriminant.rs:6:9: 6:10
- StorageLive(_2); // scope 0 at $DIR/discriminant.rs:6:13: 6:64
- StorageLive(_3); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-- _3 = std::option::Option::::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-+ _3 = const std::option::Option::::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ StorageLive(_3); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+- _3 = std::option::Option::::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
++ _3 = const std::option::Option::::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
// ty::Const
- // + ty: bool
+ // + ty: std::option::Option
// + val: Value(Scalar(0x01))
// mir::Constant
-- // + span: $DIR/discriminant.rs:6:39: 6:43
+- // + span: $DIR/discriminant.rs:11:39: 11:43
- // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-+ // + span: $DIR/discriminant.rs:6:34: 6:44
+- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
++ // + span: $DIR/discriminant.rs:11:34: 11:44
+ // + literal: Const { ty: std::option::Option, val: Value(Scalar(0x01)) }
-+ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) }
-+ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) }
}
bb1: {
- _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:6:59: 6:61
+ _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000000a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:59: 6:61
+ // + span: $DIR/discriminant.rs:11:59: 11:61
// + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb2: {
-- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ // ty::Const
-+ // + ty: bool
-+ // + val: Value(Scalar(0x01))
-+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:26: 6:30
-+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+ switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
}
bb3: {
- _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:6:47: 6:49
+ _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:11:47: 11:49
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:47: 6:49
+ // + span: $DIR/discriminant.rs:11:47: 11:49
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb4: {
- _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:6:13: 6:68
+ _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:67: 6:68
+ // + span: $DIR/discriminant.rs:11:67: 11:68
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
- StorageDead(_2); // scope 0 at $DIR/discriminant.rs:6:67: 6:68
- StorageDead(_3); // scope 0 at $DIR/discriminant.rs:6:68: 6:69
- _0 = const (); // scope 0 at $DIR/discriminant.rs:5:11: 7:2
+ StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68
+ StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69
+ _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2
// ty::Const
// + ty: ()
// + val: Value(Scalar())
// mir::Constant
- // + span: $DIR/discriminant.rs:5:11: 7:2
+ // + span: $DIR/discriminant.rs:10:11: 12:2
// + literal: Const { ty: (), val: Value(Scalar()) }
- StorageDead(_1); // scope 0 at $DIR/discriminant.rs:7:1: 7:2
- return; // scope 0 at $DIR/discriminant.rs:7:2: 7:2
+ StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2
+ return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2
}
}
diff --git a/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff
index ec0341e3de251..75b4b7e5a62ba 100644
--- a/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff
@@ -2,100 +2,93 @@
+ // MIR for `main` after ConstProp
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11
- let _1: i32; // in scope 0 at $DIR/discriminant.rs:6:9: 6:10
- let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:6:13: 6:64
- let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44
- let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:6:21: 6:31
+ let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11
+ let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44
+ let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31
scope 1 {
- debug x => _1; // in scope 1 at $DIR/discriminant.rs:6:9: 6:10
+ debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/discriminant.rs:6:9: 6:10
- StorageLive(_2); // scope 0 at $DIR/discriminant.rs:6:13: 6:64
- StorageLive(_3); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-- _3 = std::option::Option::::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-+ _3 = const std::option::Option::::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ StorageLive(_3); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+- _3 = std::option::Option::::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
++ _3 = const std::option::Option::::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
// ty::Const
- // + ty: bool
+ // + ty: std::option::Option
// + val: Value(Scalar(0x01))
// mir::Constant
-- // + span: $DIR/discriminant.rs:6:39: 6:43
+- // + span: $DIR/discriminant.rs:11:39: 11:43
- // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-+ // + span: $DIR/discriminant.rs:6:34: 6:44
+- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
++ // + span: $DIR/discriminant.rs:11:34: 11:44
+ // + literal: Const { ty: std::option::Option, val: Value(Scalar(0x01)) }
-+ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x0000000000000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) }
-+ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x0000000000000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) }
}
bb1: {
- _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:6:59: 6:61
+ _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000000a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:59: 6:61
+ // + span: $DIR/discriminant.rs:11:59: 11:61
// + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb2: {
-- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ // ty::Const
-+ // + ty: bool
-+ // + val: Value(Scalar(0x01))
-+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:26: 6:30
-+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+ switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
}
bb3: {
- _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:6:47: 6:49
+ _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:11:47: 11:49
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:47: 6:49
+ // + span: $DIR/discriminant.rs:11:47: 11:49
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb4: {
- _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:6:13: 6:68
+ _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:67: 6:68
+ // + span: $DIR/discriminant.rs:11:67: 11:68
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
- StorageDead(_2); // scope 0 at $DIR/discriminant.rs:6:67: 6:68
- StorageDead(_3); // scope 0 at $DIR/discriminant.rs:6:68: 6:69
- _0 = const (); // scope 0 at $DIR/discriminant.rs:5:11: 7:2
+ StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68
+ StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69
+ _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2
// ty::Const
// + ty: ()
// + val: Value(Scalar())
// mir::Constant
- // + span: $DIR/discriminant.rs:5:11: 7:2
+ // + span: $DIR/discriminant.rs:10:11: 12:2
// + literal: Const { ty: (), val: Value(Scalar()) }
- StorageDead(_1); // scope 0 at $DIR/discriminant.rs:7:1: 7:2
- return; // scope 0 at $DIR/discriminant.rs:7:2: 7:2
+ StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2
+ return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2
}
}
From 9ceb9bb20324630380153c1db5aeb56a433ab8d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?=
Date: Tue, 2 Jun 2020 22:35:31 +0200
Subject: [PATCH 015/123] Move copying of self-contained objects to new
function
---
src/bootstrap/compile.rs | 88 ++++++++++++++++++++++++++++------------
1 file changed, 63 insertions(+), 25 deletions(-)
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index c09b73b042013..56d72d72b6109 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -74,6 +74,7 @@ impl Step for Std {
// Even if we're not building std this stage, the new sysroot must
// still contain the third party objects needed by various targets.
copy_third_party_objects(builder, &compiler, target);
+ copy_self_contained_objects(builder, &compiler, target);
builder.ensure(StdLink {
compiler: compiler_to_use,
@@ -84,6 +85,7 @@ impl Step for Std {
}
target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
+ target_deps.extend(copy_self_contained_objects(builder, &compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
std_cargo(builder, target, compiler.stage, &mut cargo);
@@ -109,6 +111,19 @@ impl Step for Std {
}
}
+fn copy_and_stamp(
+ builder: &Builder<'_>,
+ libdir: &Path,
+ sourcedir: &Path,
+ name: &str,
+ target_deps: &mut Vec,
+) {
+ let target = libdir.join(name);
+ builder.copy(&sourcedir.join(name), &target);
+
+ target_deps.push((target, dependency_type));
+}
+
/// Copies third party objects needed by various targets.
fn copy_third_party_objects(
builder: &Builder<'_>,
@@ -116,32 +131,8 @@ fn copy_third_party_objects(
target: Interned,
) -> Vec {
let libdir = builder.sysroot_libdir(*compiler, target);
-
let mut target_deps = vec![];
- let mut copy_and_stamp = |sourcedir: &Path, name: &str| {
- let target = libdir.join(name);
- builder.copy(&sourcedir.join(name), &target);
- target_deps.push(target);
- };
-
- // Copies the CRT objects.
- //
- // rustc historically provides a more self-contained installation for musl targets
- // not requiring the presence of a native musl toolchain. For example, it can fall back
- // to using gcc from a glibc-targeting toolchain for linking.
- // To do that we have to distribute musl startup objects as a part of Rust toolchain
- // and link with them manually in the self-contained mode.
- if target.contains("musl") {
- let srcdir = builder.musl_root(target).unwrap().join("lib");
- for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
- copy_and_stamp(&srcdir, obj);
- }
- } else if target.ends_with("-wasi") {
- let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi");
- copy_and_stamp(&srcdir, "crt1.o");
- }
-
// Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx.
//
// This target needs to be linked to Fortanix's port of llvm's libunwind.
@@ -151,7 +142,13 @@ fn copy_third_party_objects(
let src_path_env = "X86_FORTANIX_SGX_LIBS";
let src =
env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env));
- copy_and_stamp(Path::new(&src), "libunwind.a");
+ copy_and_stamp(
+ builder,
+ &*libdir,
+ Path::new(&src),
+ "libunwind.a",
+ &mut target_deps,
+ );
}
if builder.config.sanitizers && compiler.stage != 0 {
@@ -163,6 +160,47 @@ fn copy_third_party_objects(
target_deps
}
+/// Copies third party objects needed by various targets for self-contained linkage.
+fn copy_self_contained_objects(
+ builder: &Builder<'_>,
+ compiler: &Compiler,
+ target: Interned,
+) -> Vec {
+ let libdir = builder.sysroot_libdir(*compiler, target);
+ let mut target_deps = vec![];
+
+ // Copies the CRT objects.
+ //
+ // rustc historically provides a more self-contained installation for musl targets
+ // not requiring the presence of a native musl toolchain. For example, it can fall back
+ // to using gcc from a glibc-targeting toolchain for linking.
+ // To do that we have to distribute musl startup objects as a part of Rust toolchain
+ // and link with them manually in the self-contained mode.
+ if target.contains("musl") {
+ let srcdir = builder.musl_root(target).unwrap().join("lib");
+ for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
+ copy_and_stamp(
+ builder,
+ &libdir_self_contained,
+ &srcdir,
+ obj,
+ &mut target_deps,
+ );
+ }
+ } else if target.ends_with("-wasi") {
+ let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi");
+ copy_and_stamp(
+ builder,
+ &libdir_self_contained,
+ &srcdir,
+ "crt1.o",
+ &mut target_deps,
+ );
+ }
+
+ target_deps
+}
+
/// Configure cargo to compile the standard library, adding appropriate env vars
/// and such.
pub fn std_cargo(builder: &Builder<'_>, target: Interned, stage: u32, cargo: &mut Cargo) {
From 638ebbc5859a38794408a988ffec6f54e0dc0f0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?=
Date: Tue, 2 Jun 2020 23:18:41 +0200
Subject: [PATCH 016/123] Move copying of MinGW CRT to the better location
---
src/bootstrap/compile.rs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 56d72d72b6109..4f58e55f21401 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -196,6 +196,13 @@ fn copy_self_contained_objects(
"crt1.o",
&mut target_deps,
);
+ } else if target.contains("windows-gnu") {
+ for obj in ["crt2.o", "dllcrt2.o"].iter() {
+ let src = compiler_file(builder, builder.cc(target), target, obj);
+ let target = libdir.join(obj);
+ builder.copy(&src, &target);
+ target_deps.push(target);
+ }
}
target_deps
@@ -419,13 +426,6 @@ impl Step for StartupObjects {
target_deps.push(target);
}
- for obj in ["crt2.o", "dllcrt2.o"].iter() {
- let src = compiler_file(builder, builder.cc(target), target, obj);
- let target = sysroot_dir.join(obj);
- builder.copy(&src, &target);
- target_deps.push(target);
- }
-
target_deps
}
}
From 961974fe0348f479255f9e95b5924419c2c15a77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?=
Date: Wed, 3 Jun 2020 00:56:27 +0200
Subject: [PATCH 017/123] Use enum to distinguish dependency type
---
src/bootstrap/compile.rs | 52 ++++++++++++++++++++++++----------------
src/bootstrap/dist.rs | 6 ++---
src/bootstrap/lib.rs | 22 ++++++++++++++---
3 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 4f58e55f21401..5fae7277149d2 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -23,7 +23,7 @@ use crate::builder::Cargo;
use crate::dist;
use crate::native;
use crate::util::{exe, is_dylib, symlink_dir};
-use crate::{Compiler, GitRepo, Mode};
+use crate::{Compiler, DependencyType, GitRepo, Mode};
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
@@ -84,7 +84,7 @@ impl Step for Std {
return;
}
- target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
+ target_deps.extend(copy_third_party_objects(builder, &compiler, target));
target_deps.extend(copy_self_contained_objects(builder, &compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
@@ -116,7 +116,8 @@ fn copy_and_stamp(
libdir: &Path,
sourcedir: &Path,
name: &str,
- target_deps: &mut Vec,
+ target_deps: &mut Vec<(PathBuf, DependencyType)>,
+ dependency_type: DependencyType,
) {
let target = libdir.join(name);
builder.copy(&sourcedir.join(name), &target);
@@ -129,7 +130,7 @@ fn copy_third_party_objects(
builder: &Builder<'_>,
compiler: &Compiler,
target: Interned,
-) -> Vec {
+) -> Vec<(PathBuf, DependencyType)> {
let libdir = builder.sysroot_libdir(*compiler, target);
let mut target_deps = vec![];
@@ -148,13 +149,18 @@ fn copy_third_party_objects(
Path::new(&src),
"libunwind.a",
&mut target_deps,
+ DependencyType::Target,
);
}
if builder.config.sanitizers && compiler.stage != 0 {
// The sanitizers are only copied in stage1 or above,
// to avoid creating dependency on LLVM.
- target_deps.extend(copy_sanitizers(builder, &compiler, target));
+ target_deps.extend(
+ copy_sanitizers(builder, &compiler, target)
+ .into_iter()
+ .map(|d| (d, DependencyType::Target)),
+ );
}
target_deps
@@ -165,7 +171,7 @@ fn copy_self_contained_objects(
builder: &Builder<'_>,
compiler: &Compiler,
target: Interned,
-) -> Vec {
+) -> Vec<(PathBuf, DependencyType)> {
let libdir = builder.sysroot_libdir(*compiler, target);
let mut target_deps = vec![];
@@ -185,6 +191,7 @@ fn copy_self_contained_objects(
&srcdir,
obj,
&mut target_deps,
+ DependencyType::TargetSelfContained,
);
}
} else if target.ends_with("-wasi") {
@@ -195,13 +202,14 @@ fn copy_self_contained_objects(
&srcdir,
"crt1.o",
&mut target_deps,
+ DependencyType::TargetSelfContained,
);
} else if target.contains("windows-gnu") {
for obj in ["crt2.o", "dllcrt2.o"].iter() {
let src = compiler_file(builder, builder.cc(target), target, obj);
let target = libdir.join(obj);
builder.copy(&src, &target);
- target_deps.push(target);
+ target_deps.push((target, DependencyType::TargetSelfContained));
}
}
@@ -370,7 +378,7 @@ pub struct StartupObjects {
}
impl Step for StartupObjects {
- type Output = Vec;
+ type Output = Vec<(PathBuf, DependencyType)>;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/rtstartup")
@@ -389,7 +397,7 @@ impl Step for StartupObjects {
/// They don't require any library support as they're just plain old object
/// files, so we just use the nightly snapshot compiler to always build them (as
/// no other compilers are guaranteed to be available).
- fn run(self, builder: &Builder<'_>) -> Vec {
+ fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
let for_compiler = self.compiler;
let target = self.target;
if !target.contains("windows-gnu") {
@@ -423,7 +431,7 @@ impl Step for StartupObjects {
let target = sysroot_dir.join((*file).to_string() + ".o");
builder.copy(dst_file, &target);
- target_deps.push(target);
+ target_deps.push((target, DependencyType::Target));
}
target_deps
@@ -838,8 +846,8 @@ pub fn add_to_sysroot(
) {
t!(fs::create_dir_all(&sysroot_dst));
t!(fs::create_dir_all(&sysroot_host_dst));
- for (path, host) in builder.read_stamp_file(stamp) {
- if host {
+ for (path, dependency_type) in builder.read_stamp_file(stamp) {
+ if dependency_type == DependencyType::Host {
builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap()));
} else {
builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
@@ -852,7 +860,7 @@ pub fn run_cargo(
cargo: Cargo,
tail_args: Vec,
stamp: &Path,
- additional_target_deps: Vec,
+ additional_target_deps: Vec<(PathBuf, DependencyType)>,
is_check: bool,
) -> Vec {
if builder.config.dry_run {
@@ -903,7 +911,7 @@ pub fn run_cargo(
if filename.starts_with(&host_root_dir) {
// Unless it's a proc macro used in the compiler
if crate_types.iter().any(|t| t == "proc-macro") {
- deps.push((filename.to_path_buf(), true));
+ deps.push((filename.to_path_buf(), DependencyType::Host));
}
continue;
}
@@ -911,7 +919,7 @@ pub fn run_cargo(
// If this was output in the `deps` dir then this is a precise file
// name (hash included) so we start tracking it.
if filename.starts_with(&target_deps_dir) {
- deps.push((filename.to_path_buf(), false));
+ deps.push((filename.to_path_buf(), DependencyType::Target));
continue;
}
@@ -963,17 +971,21 @@ pub fn run_cargo(
let candidate = format!("{}.lib", path_to_add);
let candidate = PathBuf::from(candidate);
if candidate.exists() {
- deps.push((candidate, false));
+ deps.push((candidate, DependencyType::Target));
}
}
- deps.push((path_to_add.into(), false));
+ deps.push((path_to_add.into(), DependencyType::Target));
}
- deps.extend(additional_target_deps.into_iter().map(|d| (d, false)));
+ deps.extend(additional_target_deps);
deps.sort();
let mut new_contents = Vec::new();
- for (dep, proc_macro) in deps.iter() {
- new_contents.extend(if *proc_macro { b"h" } else { b"t" });
+ for (dep, dependency_type) in deps.iter() {
+ new_contents.extend(match *dependency_type {
+ DependencyType::Host => b"h",
+ DependencyType::Target => b"t",
+ DependencyType::TargetSelfContained => b"s",
+ });
new_contents.extend(dep.to_str().unwrap().as_bytes());
new_contents.extend(b"\0");
}
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 5e966d7055bf3..77dd9c784badf 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -22,7 +22,7 @@ use crate::channel;
use crate::compile;
use crate::tool::{self, Tool};
use crate::util::{exe, is_dylib, timeit};
-use crate::{Compiler, Mode, LLVM_TOOLS};
+use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
use time::{self, Timespec};
pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
@@ -651,8 +651,8 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
let dst = image.join("lib/rustlib").join(target).join("lib");
t!(fs::create_dir_all(&dst));
- for (path, host) in builder.read_stamp_file(stamp) {
- if !host || builder.config.build == target {
+ for (path, dependency_type) in builder.read_stamp_file(stamp) {
+ if dependency_type != DependencyType::Host || builder.config.build == target {
builder.copy(&path, &dst.join(path.file_name().unwrap()));
}
}
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 8d8a036caef88..db861cb701371 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -280,6 +280,17 @@ impl Crate {
}
}
+/// When building Rust various objects are handled differently.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum DependencyType {
+ /// Libraries originating from proc-macros.
+ Host,
+ /// Typical Rust libraries.
+ Target,
+ /// Non Rust libraries and objects shipped to ease usage of certain targets.
+ TargetSelfContained,
+}
+
/// The various "modes" of invoking Cargo.
///
/// These entries currently correspond to the various output directories of the
@@ -1097,7 +1108,7 @@ impl Build {
ret
}
- fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> {
+ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
if self.config.dry_run {
return Vec::new();
}
@@ -1110,9 +1121,14 @@ impl Build {
if part.is_empty() {
continue;
}
- let host = part[0] as char == 'h';
+ let dependency_type = match part[0] as char {
+ 'h' => DependencyType::Host,
+ 's' => DependencyType::TargetSelfContained,
+ 't' => DependencyType::Target,
+ _ => unreachable!(),
+ };
let path = PathBuf::from(t!(str::from_utf8(&part[1..])));
- paths.push((path, host));
+ paths.push((path, dependency_type));
}
paths
}
From 5d298836f2254144f80e56ee37af44ac79f3eb2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?=
Date: Thu, 11 Jun 2020 18:12:19 +0200
Subject: [PATCH 018/123] Move some libs to self-contained directory
---
src/bootstrap/compile.rs | 24 +++++++++++++++++-------
src/bootstrap/dist.rs | 13 +++++++++++--
src/librustc_codegen_ssa/back/link.rs | 7 +++++++
3 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 5fae7277149d2..4b739da91ce13 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -172,7 +172,14 @@ fn copy_self_contained_objects(
compiler: &Compiler,
target: Interned,
) -> Vec<(PathBuf, DependencyType)> {
- let libdir = builder.sysroot_libdir(*compiler, target);
+ // cfg(bootstrap)
+ // Remove when upgrading bootstrap compiler.
+ let libdir_self_contained = if compiler.stage == 0 {
+ builder.sysroot_libdir(*compiler, target).to_path_buf()
+ } else {
+ builder.sysroot_libdir(*compiler, target).join("self-contained")
+ };
+ t!(fs::create_dir_all(&libdir_self_contained));
let mut target_deps = vec![];
// Copies the CRT objects.
@@ -207,7 +214,7 @@ fn copy_self_contained_objects(
} else if target.contains("windows-gnu") {
for obj in ["crt2.o", "dllcrt2.o"].iter() {
let src = compiler_file(builder, builder.cc(target), target, obj);
- let target = libdir.join(obj);
+ let target = libdir_self_contained.join(obj);
builder.copy(&src, &target);
target_deps.push((target, DependencyType::TargetSelfContained));
}
@@ -844,14 +851,17 @@ pub fn add_to_sysroot(
sysroot_host_dst: &Path,
stamp: &Path,
) {
+ let self_contained_dst = &sysroot_dst.join("self-contained");
t!(fs::create_dir_all(&sysroot_dst));
t!(fs::create_dir_all(&sysroot_host_dst));
+ t!(fs::create_dir_all(&self_contained_dst));
for (path, dependency_type) in builder.read_stamp_file(stamp) {
- if dependency_type == DependencyType::Host {
- builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap()));
- } else {
- builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
- }
+ let dst = match dependency_type {
+ DependencyType::Host => sysroot_host_dst,
+ DependencyType::Target => sysroot_dst,
+ DependencyType::TargetSelfContained => self_contained_dst,
+ };
+ builder.copy(&path, &dst.join(path.file_name().unwrap()));
}
}
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 77dd9c784badf..08737d9a0474e 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -321,7 +321,12 @@ fn make_win_dist(
);
//Copy platform libs to platform-specific lib directory
- let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
+ let target_lib_dir = plat_root
+ .join("lib")
+ .join("rustlib")
+ .join(target_triple)
+ .join("lib")
+ .join("self-contained");
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
for src in target_libs {
builder.copy_to_folder(&src, &target_lib_dir);
@@ -650,9 +655,13 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
/// Copy stamped files into an image's `target/lib` directory.
fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
let dst = image.join("lib/rustlib").join(target).join("lib");
+ let self_contained_dst = dst.join("self-contained");
t!(fs::create_dir_all(&dst));
+ t!(fs::create_dir_all(&self_contained_dst));
for (path, dependency_type) in builder.read_stamp_file(stamp) {
- if dependency_type != DependencyType::Host || builder.config.build == target {
+ if dependency_type == DependencyType::TargetSelfContained {
+ builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap()));
+ } else if dependency_type == DependencyType::Target || builder.config.build == target {
builder.copy(&path, &dst.join(path.file_name().unwrap()));
}
}
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 53e3da3c0baf0..c57b01dff2801 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1075,6 +1075,10 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
if file_path.exists() {
return file_path;
}
+ let file_path = fs.get_lib_path().join("self-contained").join(name);
+ if file_path.exists() {
+ return file_path;
+ }
for search_path in fs.search_paths() {
let file_path = search_path.dir.join(name);
if file_path.exists() {
@@ -1470,6 +1474,9 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
// The location of crates will be determined as needed.
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+
+ let lib_path = sess.target_filesearch(PathKind::All).get_lib_path().join("self-contained");
+ cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
}
/// Add options making relocation sections in the produced ELF files read-only
From e9ac01a9beeae77a15badcec094a7a4da0bebecb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?=
Date: Mon, 8 Jun 2020 12:47:56 +0200
Subject: [PATCH 019/123] Get self-contained directory path via dedicated
function
---
src/librustc_codegen_ssa/back/link.rs | 4 ++--
src/librustc_session/filesearch.rs | 4 ++++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index c57b01dff2801..1eef86f6c931c 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1075,7 +1075,7 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
if file_path.exists() {
return file_path;
}
- let file_path = fs.get_lib_path().join("self-contained").join(name);
+ let file_path = fs.get_selfcontained_lib_path().join(name);
if file_path.exists() {
return file_path;
}
@@ -1475,7 +1475,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
- let lib_path = sess.target_filesearch(PathKind::All).get_lib_path().join("self-contained");
+ let lib_path = sess.target_filesearch(PathKind::All).get_selfcontained_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
}
diff --git a/src/librustc_session/filesearch.rs b/src/librustc_session/filesearch.rs
index e98746231fb30..37d7b0c7e1f71 100644
--- a/src/librustc_session/filesearch.rs
+++ b/src/librustc_session/filesearch.rs
@@ -41,6 +41,10 @@ impl<'a> FileSearch<'a> {
make_target_lib_path(self.sysroot, self.triple)
}
+ pub fn get_selfcontained_lib_path(&self) -> PathBuf {
+ self.get_lib_path().join("self-contained")
+ }
+
pub fn search(&self, mut pick: F)
where
F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
From 43905cd7501fd37090cb9de6069faaba761e514a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?=
Date: Mon, 8 Jun 2020 13:20:26 +0200
Subject: [PATCH 020/123] Move shipped MinGW linker to self-contained dir
---
src/bootstrap/dist.rs | 7 ++++++-
src/librustc_session/filesearch.rs | 2 +-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 08737d9a0474e..df1253f3f9e7c 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -306,7 +306,12 @@ fn make_win_dist(
}
//Copy platform tools to platform-specific bin directory
- let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
+ let target_bin_dir = plat_root
+ .join("lib")
+ .join("rustlib")
+ .join(target_triple)
+ .join("bin")
+ .join("self-contained");
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
for src in target_tools {
builder.copy_to_folder(&src, &target_bin_dir);
diff --git a/src/librustc_session/filesearch.rs b/src/librustc_session/filesearch.rs
index 37d7b0c7e1f71..5586b82b0edc0 100644
--- a/src/librustc_session/filesearch.rs
+++ b/src/librustc_session/filesearch.rs
@@ -98,7 +98,7 @@ impl<'a> FileSearch<'a> {
p.push(RUST_LIB_DIR);
p.push(&self.triple);
p.push("bin");
- vec![p]
+ vec![p.clone(), p.join("self-contained")]
}
}
From f0d2e78d39d0efdb431af0b59c498d532d8146e2 Mon Sep 17 00:00:00 2001
From: Ralf Jung
Date: Fri, 12 Jun 2020 18:17:30 +0200
Subject: [PATCH 021/123] add raw_ref macros
---
src/libcore/ptr/mod.rs | 67 ++++++++++++++++++++++++++++++++++++++++++
src/libstd/lib.rs | 1 +
2 files changed, 68 insertions(+)
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 777284ca5c096..199f08c3d5058 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -1399,3 +1399,70 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
+
+/// Create a `const` raw pointer to a place, without creating an intermediate reference.
+///
+/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
+/// and points to initialized data. For cases where those requirements do not hold,
+/// raw pointers should be used instead. However, `&expr as *const _` creates a reference
+/// before casting it to a raw pointer, and that reference is subject to the same rules
+/// as all other references. This macro can create a raw pointer *without* creating
+/// a reference first.
+///
+/// # Example
+///
+/// ```
+/// #![feature(raw_ref_macros)]
+/// use std::ptr;
+///
+/// #[repr(packed)]
+/// struct Packed {
+/// f1: u8,
+/// f2: u16,
+/// }
+///
+/// let packed = Packed { f1: 1, f2: 2 };
+/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
+/// let raw_f2 = ptr::raw_const!(packed.f2);
+/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
+/// ```
+#[unstable(feature = "raw_ref_macros", issue = "none")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(raw_ref_op)]
+pub macro raw_const($e:expr) {
+ &raw const $e
+}
+
+/// Create a `mut` raw pointer to a place, without creating an intermediate reference.
+///
+/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
+/// and points to initialized data. For cases where those requirements do not hold,
+/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference
+/// before casting it to a raw pointer, and that reference is subject to the same rules
+/// as all other references. This macro can create a raw pointer *without* creating
+/// a reference first.
+///
+/// # Example
+///
+/// ```
+/// #![feature(raw_ref_macros)]
+/// use std::ptr;
+///
+/// #[repr(packed)]
+/// struct Packed {
+/// f1: u8,
+/// f2: u16,
+/// }
+///
+/// let mut packed = Packed { f1: 1, f2: 2 };
+/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
+/// let raw_f2 = ptr::raw_mut!(packed.f2);
+/// unsafe { raw_f2.write_unaligned(42); }
+/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
+/// ```
+#[unstable(feature = "raw_ref_macros", issue = "none")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(raw_ref_op)]
+pub macro raw_mut($e:expr) {
+ &raw mut $e
+}
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index d6493454db591..ef699ede2a140 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -298,6 +298,7 @@
#![feature(prelude_import)]
#![feature(ptr_internals)]
#![feature(raw)]
+#![feature(raw_ref_macros)]
#![feature(renamed_spin_loop)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
From d40e624a3625c7c2d68c949435fd883cd43dd065 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?=
Date: Fri, 5 Jun 2020 00:00:00 +0000
Subject: [PATCH 022/123] compiletest: Add directives to detect sanitizer
support
Add needs-sanitizer-{address,leak,memory,thread} directive indicating
that test requires target with support for specific sanitizer.
This is an addition to the existing needs-sanitizer-support directive
indicating that test requires a sanitizer runtime library.
---
.../codegen/sanitizer-memory-track-orgins.rs | 4 +--
.../codegen/sanitizer-no-sanitize-inlining.rs | 6 ++--
src/test/codegen/sanitizer-no-sanitize.rs | 2 +-
src/test/codegen/sanitizer-recover.rs | 5 ++--
.../sanitizer-cdylib-link/Makefile | 2 +-
.../sanitizer-dylib-link/Makefile | 2 +-
.../sanitizer-staticlib-link/Makefile | 2 +-
src/test/rustdoc/sanitizer-option.rs | 1 +
src/test/ui/sanitize/address.rs | 2 +-
src/test/ui/sanitize/badfree.rs | 2 +-
src/test/ui/sanitize/cfg.rs | 6 ++--
.../sanitize/issue-72154-lifetime-markers.rs | 2 +-
src/test/ui/sanitize/leak.rs | 2 +-
src/test/ui/sanitize/memory.rs | 3 +-
.../new-llvm-pass-manager-thin-lto.rs | 2 +-
src/test/ui/sanitize/thread.rs | 2 +-
src/test/ui/sanitize/use-after-scope.rs | 2 +-
src/tools/compiletest/src/header.rs | 28 +++++++++++++++----
src/tools/compiletest/src/header/tests.rs | 19 +++++++++++++
src/tools/compiletest/src/util.rs | 11 ++++++++
20 files changed, 75 insertions(+), 30 deletions(-)
diff --git a/src/test/codegen/sanitizer-memory-track-orgins.rs b/src/test/codegen/sanitizer-memory-track-orgins.rs
index 8ea41c5d44bb1..4bd50508d1520 100644
--- a/src/test/codegen/sanitizer-memory-track-orgins.rs
+++ b/src/test/codegen/sanitizer-memory-track-orgins.rs
@@ -1,9 +1,7 @@
// Verifies that MemorySanitizer track-origins level can be controlled
// with -Zsanitizer-memory-track-origins option.
//
-// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-memory
// revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
//
//[MSAN-0] compile-flags: -Zsanitizer=memory
diff --git a/src/test/codegen/sanitizer-no-sanitize-inlining.rs b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
index d96e76618d325..b00441e4fc5ab 100644
--- a/src/test/codegen/sanitizer-no-sanitize-inlining.rs
+++ b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
@@ -1,11 +1,9 @@
// Verifies that no_sanitize attribute prevents inlining when
// given sanitizer is enabled, but has no effect on inlining otherwise.
//
-// needs-sanitizer-support
-// only-x86_64
-//
+// needs-sanitizer-address
+// needs-sanitizer-leak
// revisions: ASAN LSAN
-//
//[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=3
//[LSAN] compile-flags: -Zsanitizer=leak -C opt-level=3 -Z mir-opt-level=3
diff --git a/src/test/codegen/sanitizer-no-sanitize.rs b/src/test/codegen/sanitizer-no-sanitize.rs
index dfceb28c8dd10..1b2b18822e63e 100644
--- a/src/test/codegen/sanitizer-no-sanitize.rs
+++ b/src/test/codegen/sanitizer-no-sanitize.rs
@@ -1,7 +1,7 @@
// Verifies that no_sanitze attribute can be used to
// selectively disable sanitizer instrumentation.
//
-// needs-sanitizer-support
+// needs-sanitizer-address
// compile-flags: -Zsanitizer=address
#![crate_type="lib"]
diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs
index 05b4ab5653cc8..719f219ce4ef1 100644
--- a/src/test/codegen/sanitizer-recover.rs
+++ b/src/test/codegen/sanitizer-recover.rs
@@ -1,9 +1,8 @@
// Verifies that AddressSanitizer and MemorySanitizer
// recovery mode can be enabled with -Zsanitizer-recover.
//
-// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-address
+// needs-sanitizer-memory
// revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO
// no-prefer-dynamic
//
diff --git a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
index 5d46be87eac6b..b11d4c4cab7cf 100644
--- a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
@@ -1,5 +1,5 @@
# needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
# only-linux
-include ../tools.mk
diff --git a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
index f62c3a6654ed4..c2ebd2a6d8cac 100644
--- a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
@@ -1,5 +1,5 @@
# needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
# only-linux
-include ../tools.mk
diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
index f56475b441f1a..5ceff16471cee 100644
--- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
@@ -1,5 +1,5 @@
# needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
# only-linux
-include ../tools.mk
diff --git a/src/test/rustdoc/sanitizer-option.rs b/src/test/rustdoc/sanitizer-option.rs
index 6af9ed3e33f66..a79b37ee08210 100644
--- a/src/test/rustdoc/sanitizer-option.rs
+++ b/src/test/rustdoc/sanitizer-option.rs
@@ -1,4 +1,5 @@
// needs-sanitizer-support
+// needs-sanitizer-address
// compile-flags: --test -Z sanitizer=address
//
// #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern
diff --git a/src/test/ui/sanitize/address.rs b/src/test/ui/sanitize/address.rs
index f8650cd86d51e..cee73b0425ad5 100644
--- a/src/test/ui/sanitize/address.rs
+++ b/src/test/ui/sanitize/address.rs
@@ -1,5 +1,5 @@
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Z sanitizer=address -O -g
//
diff --git a/src/test/ui/sanitize/badfree.rs b/src/test/ui/sanitize/badfree.rs
index 1ca082c8b4704..095a6f4697b1c 100644
--- a/src/test/ui/sanitize/badfree.rs
+++ b/src/test/ui/sanitize/badfree.rs
@@ -1,5 +1,5 @@
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Z sanitizer=address -O
//
diff --git a/src/test/ui/sanitize/cfg.rs b/src/test/ui/sanitize/cfg.rs
index 9c198543a8664..79dfe58f04d0b 100644
--- a/src/test/ui/sanitize/cfg.rs
+++ b/src/test/ui/sanitize/cfg.rs
@@ -2,8 +2,10 @@
// the `#[cfg(sanitize = "option")]` attribute is configured.
// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-address
+// needs-sanitizer-leak
+// needs-sanitizer-memory
+// needs-sanitizer-thread
// check-pass
// revisions: address leak memory thread
//[address]compile-flags: -Zsanitizer=address --cfg address
diff --git a/src/test/ui/sanitize/issue-72154-lifetime-markers.rs b/src/test/ui/sanitize/issue-72154-lifetime-markers.rs
index 458f99143b648..b2e182238ce28 100644
--- a/src/test/ui/sanitize/issue-72154-lifetime-markers.rs
+++ b/src/test/ui/sanitize/issue-72154-lifetime-markers.rs
@@ -4,7 +4,7 @@
// miscompilation which was subsequently detected by AddressSanitizer as UB.
//
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Copt-level=0 -Zsanitizer=address
// run-pass
diff --git a/src/test/ui/sanitize/leak.rs b/src/test/ui/sanitize/leak.rs
index 5c2f2cb4e868b..c9f10fe4f467e 100644
--- a/src/test/ui/sanitize/leak.rs
+++ b/src/test/ui/sanitize/leak.rs
@@ -1,5 +1,5 @@
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-leak
//
// compile-flags: -Z sanitizer=leak -O
//
diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs
index 3e1cf4509a31f..a26649a580013 100644
--- a/src/test/ui/sanitize/memory.rs
+++ b/src/test/ui/sanitize/memory.rs
@@ -1,6 +1,5 @@
// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-memory
//
// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
//
diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
index d0984bbe65fd5..64d6ccf340916 100644
--- a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
+++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
@@ -4,7 +4,7 @@
//
// min-llvm-version 9.0
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// no-prefer-dynamic
// revisions: opt0 opt1
diff --git a/src/test/ui/sanitize/thread.rs b/src/test/ui/sanitize/thread.rs
index 26590be8b1870..c70cf5accc077 100644
--- a/src/test/ui/sanitize/thread.rs
+++ b/src/test/ui/sanitize/thread.rs
@@ -11,7 +11,7 @@
// would occasionally fail, making test flaky.
//
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-thread
//
// compile-flags: -Z sanitizer=thread -O
//
diff --git a/src/test/ui/sanitize/use-after-scope.rs b/src/test/ui/sanitize/use-after-scope.rs
index 6a2067e157af5..30be2ae6f0906 100644
--- a/src/test/ui/sanitize/use-after-scope.rs
+++ b/src/test/ui/sanitize/use-after-scope.rs
@@ -1,5 +1,5 @@
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Zsanitizer=address
// run-fail
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 9d1940dd4d6c2..9614707433e13 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -43,6 +43,10 @@ impl EarlyProps {
let mut props = EarlyProps::default();
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
+ let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
iter_header(testfile, None, rdr, &mut |ln| {
// we should check if any only- exists and if it exists
@@ -74,7 +78,25 @@ impl EarlyProps {
props.ignore = true;
}
- if !rustc_has_sanitizer_support && config.parse_needs_sanitizer_support(ln) {
+ if !rustc_has_sanitizer_support
+ && config.parse_name_directive(ln, "needs-sanitizer-support")
+ {
+ props.ignore = true;
+ }
+
+ if !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address") {
+ props.ignore = true;
+ }
+
+ if !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak") {
+ props.ignore = true;
+ }
+
+ if !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory") {
+ props.ignore = true;
+ }
+
+ if !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread") {
props.ignore = true;
}
@@ -829,10 +851,6 @@ impl Config {
self.parse_name_directive(line, "needs-profiler-support")
}
- fn parse_needs_sanitizer_support(&self, line: &str) -> bool {
- self.parse_name_directive(line, "needs-sanitizer-support")
- }
-
/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
/// or `normalize-stderr-32bit`.
fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 31d991e0c2f87..036409fbf070f 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -195,3 +195,22 @@ fn debugger() {
config.debugger = Some(Debugger::Lldb);
assert!(parse_rs(&config, "// ignore-lldb").ignore);
}
+
+#[test]
+fn sanitizers() {
+ let mut config = config();
+
+ // Target that supports all sanitizers:
+ config.target = "x86_64-unknown-linux-gnu".to_owned();
+ assert!(!parse_rs(&config, "// needs-sanitizer-address").ignore);
+ assert!(!parse_rs(&config, "// needs-sanitizer-leak").ignore);
+ assert!(!parse_rs(&config, "// needs-sanitizer-memory").ignore);
+ assert!(!parse_rs(&config, "// needs-sanitizer-thread").ignore);
+
+ // Target that doesn't support sanitizers:
+ config.target = "wasm32-unknown-emscripten".to_owned();
+ assert!(parse_rs(&config, "// needs-sanitizer-address").ignore);
+ assert!(parse_rs(&config, "// needs-sanitizer-leak").ignore);
+ assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore);
+ assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore);
+}
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index c61bee0f8d9ea..b9087dee6174c 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -81,6 +81,17 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
("xcore", "xcore"),
];
+pub const ASAN_SUPPORTED_TARGETS: &'static [&'static str] =
+ &["aarch64-fuchsia", "x86_64-apple-darwin", "x86_64-fuchsia", "x86_64-unknown-linux-gnu"];
+
+pub const LSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+ &["x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
+pub const MSAN_SUPPORTED_TARGETS: &'static [&'static str] = &["x86_64-unknown-linux-gnu"];
+
+pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+ &["x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
pub fn matches_os(triple: &str, name: &str) -> bool {
// For the wasm32 bare target we ignore anything also ignored on emscripten
// and then we also recognize `wasm32-bare` as the os for the target
From 724dfba460e2c98311cacb5d4f6bb6da36ceec67 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez
Date: Sat, 13 Jun 2020 15:05:37 +0200
Subject: [PATCH 023/123] Clean up some weird command strings
---
src/librustdoc/lib.rs | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 82d6cda986a9a..95d113166e001 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -165,9 +165,8 @@ fn opts() -> Vec {
o.optmulti(
"",
"passes",
- "list of passes to also run, you might want \
- to pass it multiple times; a value of `list` \
- will print available passes",
+ "list of passes to also run, you might want to pass it multiple times; a value of \
+ `list` will print available passes",
"PASSES",
)
}),
@@ -248,8 +247,8 @@ fn opts() -> Vec {
"e",
"extend-css",
"To add some CSS rules with a given file to generate doc with your \
- own theme. However, your theme might break if the rustdoc's generated HTML \
- changes, so be careful!",
+ own theme. However, your theme might break if the rustdoc's generated HTML \
+ changes, so be careful!",
"PATH",
)
}),
@@ -262,7 +261,7 @@ fn opts() -> Vec {
"",
"playground-url",
"URL to send code snippets to, may be reset by --markdown-playground-url \
- or `#![doc(html_playground_url=...)]`",
+ or `#![doc(html_playground_url=...)]`",
"URL",
)
}),
@@ -276,8 +275,7 @@ fn opts() -> Vec {
o.optflag(
"",
"sort-modules-by-appearance",
- "sort modules by where they appear in the \
- program, rather than alphabetically",
+ "sort modules by where they appear in the program, rather than alphabetically",
)
}),
stable("theme", |o| {
@@ -358,7 +356,7 @@ fn opts() -> Vec {
"",
"static-root-path",
"Path string to force loading static files from in output pages. \
- If not set, uses combinations of '../' to reach the documentation root.",
+ If not set, uses combinations of '../' to reach the documentation root.",
"PATH",
)
}),
From 0687b78d56b93d28ceeaa05e794849757d7341a4 Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Sat, 13 Jun 2020 10:29:56 -0700
Subject: [PATCH 024/123] Speed up bootstrap a little.
---
src/bootstrap/flags.rs | 7 ++---
src/bootstrap/lib.rs | 2 +-
src/bootstrap/metadata.rs | 65 +++++++++++++++++----------------------
src/bootstrap/test.rs | 4 +--
4 files changed, 33 insertions(+), 45 deletions(-)
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index cfaa43f397095..03b7028b2fa55 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -10,12 +10,10 @@ use std::process;
use getopts::Options;
use crate::builder::Builder;
+use crate::cache::{Interned, INTERNER};
use crate::config::Config;
-use crate::metadata;
use crate::{Build, DocTests};
-use crate::cache::{Interned, INTERNER};
-
/// Deserialized version of all flags for this compile.
pub struct Flags {
pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
@@ -444,8 +442,7 @@ Arguments:
// All subcommands except `clean` can have an optional "Available paths" section
if matches.opt_present("verbose") {
let config = Config::parse(&["build".to_string()]);
- let mut build = Build::new(config);
- metadata::build(&mut build);
+ let build = Build::new(config);
let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 8d8a036caef88..a125b49fc01e6 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -271,7 +271,7 @@ struct Crate {
impl Crate {
fn is_local(&self, build: &Build) -> bool {
- self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim")
+ self.path.starts_with(&build.config.src)
}
fn local_path(&self, build: &Build) -> PathBuf {
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index 292aa3b1e24a7..185f0ddb831e7 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -35,49 +35,24 @@ struct ResolveNode {
}
pub fn build(build: &mut Build) {
- let mut resolves = Vec::new();
- build_krate(&build.std_features(), build, &mut resolves, "src/libstd");
- build_krate("", build, &mut resolves, "src/libtest");
- build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc");
-
- let mut id2name = HashMap::with_capacity(build.crates.len());
- for (name, krate) in build.crates.iter() {
- id2name.insert(krate.id.clone(), name.clone());
- }
-
- for node in resolves {
- let name = match id2name.get(&node.id) {
- Some(name) => name,
- None => continue,
- };
-
- let krate = build.crates.get_mut(name).unwrap();
- for dep in node.dependencies.iter() {
- let dep = match id2name.get(dep) {
- Some(dep) => dep,
- None => continue,
- };
- krate.deps.insert(*dep);
- }
- }
-}
-
-fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec, krate: &str) {
// Run `cargo metadata` to figure out what crates we're testing.
- //
- // Down below we're going to call `cargo test`, but to test the right set
- // of packages we're going to have to know what `-p` arguments to pass it
- // to know what crates to test. Here we run `cargo metadata` to learn about
- // the dependency graph and what `-p` arguments there are.
+ let features: Vec<_> = build
+ .std_features()
+ .split_whitespace()
+ .map(|f| format!("test/{}", f))
+ .chain(build.rustc_features().split_whitespace().map(|f| format!("rustc-main/{}", f)))
+ .collect();
let mut cargo = Command::new(&build.initial_cargo);
cargo
.arg("metadata")
.arg("--format-version")
.arg("1")
.arg("--features")
- .arg(features)
+ .arg(features.join(","))
+ .arg("-Zpackage-features")
.arg("--manifest-path")
- .arg(build.src.join(krate).join("Cargo.toml"));
+ .arg(build.src.join("Cargo.toml"))
+ .env("RUSTC_BOOTSTRAP", "1");
let output = output(&mut cargo);
let output: Output = serde_json::from_str(&output).unwrap();
for package in output.packages {
@@ -88,5 +63,23 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec =
+ build.crates.iter().map(|(name, krate)| (krate.id.clone(), name.clone())).collect();
+
+ for node in output.resolve.nodes {
+ let name = match id2name.get(&node.id) {
+ Some(name) => name,
+ None => continue,
+ };
+
+ let krate = build.crates.get_mut(name).unwrap();
+ for dep in node.dependencies.iter() {
+ let dep = match id2name.get(dep) {
+ Some(dep) => dep,
+ None => continue,
+ };
+ krate.deps.insert(*dep);
+ }
+ }
}
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 163132f563425..8659acf1cc5a5 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1654,9 +1654,7 @@ impl Step for Crate {
fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
for krate in run.builder.in_tree_crates("test") {
- if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
- run = run.path(krate.local_path(&builder).to_str().unwrap());
- }
+ run = run.path(krate.local_path(&builder).to_str().unwrap());
}
run
}
From 4606168dd508007fb1014b6ab12b27e320e07038 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?=
Date: Sat, 13 Jun 2020 11:12:29 -0700
Subject: [PATCH 025/123] Make new type param suggestion more targetted
Do not suggest new type param when encountering a missing type in an ADT
field with generic parameters.
Fix #72640.
---
src/librustc_resolve/build_reduced_graph.rs | 1 +
src/librustc_resolve/late/diagnostics.rs | 2 +-
src/librustc_resolve/lib.rs | 14 ++++++++------
.../ui/suggestions/type-not-found-in-adt-field.rs | 5 +++++
.../suggestions/type-not-found-in-adt-field.stderr | 9 +++++++++
5 files changed, 24 insertions(+), 7 deletions(-)
create mode 100644 src/test/ui/suggestions/type-not-found-in-adt-field.rs
create mode 100644 src/test/ui/suggestions/type-not-found-in-adt-field.stderr
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 2ae063660e38d..8661af6d7a1de 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -485,6 +485,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
module_path.push(Segment {
ident: Ident { name: kw::PathRoot, span: source.ident.span },
id: Some(self.r.next_node_id()),
+ has_args: false,
});
source.ident.name = crate_name;
}
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index b1a1f8725a180..28ff89f66925e 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -920,7 +920,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
path: &[Segment],
) -> Option<(Span, &'static str, String, Applicability)> {
let ident = match path {
- [segment] => segment.ident,
+ [segment] if !segment.has_args => segment.ident,
_ => return None,
};
match (
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 6bd73877fab75..f7ec919fa04e3 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -225,13 +225,15 @@ enum VisResolutionError<'a> {
ModuleOnly(Span),
}
-// A minimal representation of a path segment. We use this in resolve because
-// we synthesize 'path segments' which don't have the rest of an AST or HIR
-// `PathSegment`.
+/// A minimal representation of a path segment. We use this in resolve because we synthesize 'path
+/// segments' which don't have the rest of an AST or HIR `PathSegment`.
#[derive(Clone, Copy, Debug)]
pub struct Segment {
ident: Ident,
id: Option,
+ /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
+ /// nonsensical suggestions.
+ has_args: bool,
}
impl Segment {
@@ -240,7 +242,7 @@ impl Segment {
}
fn from_ident(ident: Ident) -> Segment {
- Segment { ident, id: None }
+ Segment { ident, id: None, has_args: false }
}
fn names_to_string(segments: &[Segment]) -> String {
@@ -250,7 +252,7 @@ impl Segment {
impl<'a> From<&'a ast::PathSegment> for Segment {
fn from(seg: &'a ast::PathSegment) -> Segment {
- Segment { ident: seg.ident, id: Some(seg.id) }
+ Segment { ident: seg.ident, id: Some(seg.id), has_args: seg.args.is_some() }
}
}
@@ -2017,7 +2019,7 @@ impl<'a> Resolver<'a> {
path, opt_ns, record_used, path_span, crate_lint,
);
- for (i, &Segment { ident, id }) in path.iter().enumerate() {
+ for (i, &Segment { ident, id, has_args: _ }) in path.iter().enumerate() {
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
let record_segment_res = |this: &mut Self, res| {
if record_used {
diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.rs b/src/test/ui/suggestions/type-not-found-in-adt-field.rs
new file mode 100644
index 0000000000000..6bd42472f5a55
--- /dev/null
+++ b/src/test/ui/suggestions/type-not-found-in-adt-field.rs
@@ -0,0 +1,5 @@
+struct S {
+ m: Vec>, //~ ERROR cannot find type `Hashmap` in this scope
+ //~^ NOTE not found in this scope
+}
+fn main() {}
diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.stderr b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr
new file mode 100644
index 0000000000000..cfad8c689d038
--- /dev/null
+++ b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Hashmap` in this scope
+ --> $DIR/type-not-found-in-adt-field.rs:2:12
+ |
+LL | m: Vec>,
+ | ^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
From d5ea0e9f8def9a3ec0eb2dd88f0465d4d1a81c21 Mon Sep 17 00:00:00 2001
From: oddg
Date: Thu, 14 May 2020 19:58:43 -0700
Subject: [PATCH 026/123] Report error when casting an C-like enum implementing
Drop
---
src/librustc_session/lint/builtin.rs | 11 ++++++++++
src/librustc_typeck/check/cast.rs | 30 +++++++++++++++++++++++++---
2 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs
index 58388bafbeddf..5a8f5c1b9fbca 100644
--- a/src/librustc_session/lint/builtin.rs
+++ b/src/librustc_session/lint/builtin.rs
@@ -534,6 +534,16 @@ declare_lint! {
@feature_gate = sym::unsafe_block_in_unsafe_fn;
}
+declare_lint! {
+ pub CENUM_IMPL_DROP_CAST,
+ Warn,
+ "a C-like enum implementing Drop is cast",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #73333 ",
+ edition: None,
+ };
+}
+
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@@ -607,6 +617,7 @@ declare_lint_pass! {
ASM_SUB_REGISTER,
UNSAFE_OP_IN_UNSAFE_FN,
INCOMPLETE_INCLUDE,
+ CENUM_IMPL_DROP_CAST,
]
}
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 46d6706cbf429..bea5e0e996658 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -609,7 +609,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
// prim -> prim
- (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
+ (Int(CEnum), Int(_)) => {
+ self.cenum_impl_drop_lint(fcx);
+ Ok(CastKind::EnumCast)
+ }
(Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
@@ -706,11 +709,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// Coerce to a raw pointer so that we generate AddressOf in MIR.
let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
- .unwrap_or_else(|_| bug!(
+ .unwrap_or_else(|_| {
+ bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
self.expr_ty,
array_ptr_type,
- ));
+ )
+ });
// this will report a type mismatch if needed
fcx.demand_eqtype(self.span, ety, m_cast.ty);
@@ -740,6 +745,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
Err(err) => Err(err),
}
}
+
+ fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
+ if let ty::Adt(d, _) = self.expr_ty.kind {
+ if d.has_dtor(fcx.tcx) {
+ fcx.tcx.struct_span_lint_hir(
+ lint::builtin::CENUM_IMPL_DROP_CAST,
+ self.expr.hir_id,
+ self.span,
+ |err| {
+ err.build(&format!(
+ "Cast `enum` implementing `Drop` `{}` to integer `{}`",
+ self.expr_ty, self.cast_ty
+ ))
+ .emit();
+ },
+ );
+ }
+ }
+ }
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
From e32db8458457849f5d894ffa4a1672b9071708f0 Mon Sep 17 00:00:00 2001
From: asrar
Date: Sun, 14 Jun 2020 21:44:11 +0530
Subject: [PATCH 027/123] Add rust features to print target features
`crt-static` is a rust specific target feature that's absent from llvm feature table, adding it there.
---
src/rustllvm/PassWrapper.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 3d252fe70afeb..7586dd91ab68b 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -425,6 +425,9 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) {
for (auto &Feature : FeatTable)
printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
printf("\n");
+ // Rust specific target features
+ printf(" %-*s - %s.\n", MaxFeatLen, "crt-static", "Enables libraries with C Run-time Libraries(CRT) to be statically linked");
+ printf("\n");
printf("Use +feature to enable a feature, or -feature to disable it.\n"
"For example, rustc -C -target-cpu=mycpu -C "
From a40156e5b7053dcc36ba1ad65fb567b183c4e1fb Mon Sep 17 00:00:00 2001
From: oddg
Date: Sun, 14 Jun 2020 15:49:20 -0700
Subject: [PATCH 028/123] UI test for deprecation warning of casting enum
implementing Drop
---
src/test/ui/cenum_impl_drop_cast.rs | 18 ++++++++++++++++++
src/test/ui/cenum_impl_drop_cast.stderr | 16 ++++++++++++++++
2 files changed, 34 insertions(+)
create mode 100644 src/test/ui/cenum_impl_drop_cast.rs
create mode 100644 src/test/ui/cenum_impl_drop_cast.stderr
diff --git a/src/test/ui/cenum_impl_drop_cast.rs b/src/test/ui/cenum_impl_drop_cast.rs
new file mode 100644
index 0000000000000..623460673bfa2
--- /dev/null
+++ b/src/test/ui/cenum_impl_drop_cast.rs
@@ -0,0 +1,18 @@
+#![deny(cenum_impl_drop_cast)]
+
+enum E {
+ A = 0,
+}
+
+impl Drop for E {
+ fn drop(&mut self) {
+ println!("Drop");
+ }
+}
+
+fn main() {
+ let e = E::A;
+ let i = e as u32;
+ //~^ ERROR Cast `enum` implementing `Drop` `E` to integer `u32`
+ //~| WARN this was previously accepted
+}
diff --git a/src/test/ui/cenum_impl_drop_cast.stderr b/src/test/ui/cenum_impl_drop_cast.stderr
new file mode 100644
index 0000000000000..5c8f86ffd72ad
--- /dev/null
+++ b/src/test/ui/cenum_impl_drop_cast.stderr
@@ -0,0 +1,16 @@
+error: Cast `enum` implementing `Drop` `E` to integer `u32`
+ --> $DIR/cenum_impl_drop_cast.rs:15:13
+ |
+LL | let i = e as u32;
+ | ^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/cenum_impl_drop_cast.rs:1:9
+ |
+LL | #![deny(cenum_impl_drop_cast)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #73333
+
+error: aborting due to previous error
+
From 607e85110ef9c79ce5a52286bb69d385471bc675 Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Sun, 14 Jun 2020 15:57:21 -0700
Subject: [PATCH 029/123] Switch bootstrap metadata to --no-deps.
This should run much faster.
There are also some drive-by cleanups here to try to simplify things.
Also, the paths for in-tree crates are now displayed as relative
in `x.py test -h -v`.
---
src/bootstrap/builder.rs | 6 +++--
src/bootstrap/doc.rs | 20 ++------------
src/bootstrap/lib.rs | 25 +++++++++++-------
src/bootstrap/metadata.rs | 55 +++++++++------------------------------
src/bootstrap/test.rs | 8 ++----
5 files changed, 37 insertions(+), 77 deletions(-)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index ffdd8485181f4..345af600c2adb 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -255,7 +255,8 @@ impl<'a> ShouldRun<'a> {
pub fn all_krates(mut self, name: &str) -> Self {
let mut set = BTreeSet::new();
for krate in self.builder.in_tree_crates(name) {
- set.insert(PathBuf::from(&krate.path));
+ let path = krate.local_path(self.builder);
+ set.insert(path);
}
self.paths.insert(PathSet::Set(set));
self
@@ -263,7 +264,8 @@ impl<'a> ShouldRun<'a> {
pub fn krate(mut self, name: &str) -> Self {
for krate in self.builder.in_tree_crates(name) {
- self.paths.insert(PathSet::one(&krate.path));
+ let path = krate.local_path(self.builder);
+ self.paths.insert(PathSet::one(path));
}
self
}
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 5c01c5e852c48..6d7fb7acfcb04 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -548,8 +548,8 @@ impl Step for Rustc {
// Find dependencies for top level crates.
let mut compiler_crates = HashSet::new();
for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
- let interned_root_crate = INTERNER.intern_str(root_crate);
- find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
+ compiler_crates
+ .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name));
}
for krate in &compiler_crates {
@@ -564,22 +564,6 @@ impl Step for Rustc {
}
}
-fn find_compiler_crates(
- builder: &Builder<'_>,
- name: &Interned,
- crates: &mut HashSet>,
-) {
- // Add current crate.
- crates.insert(*name);
-
- // Look for dependencies.
- for dep in builder.crates.get(name).unwrap().deps.iter() {
- if builder.crates.get(dep).unwrap().is_local(builder) {
- find_compiler_crates(builder, dep, crates);
- }
- }
-}
-
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rustdoc {
stage: u32,
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index a125b49fc01e6..9d3830da39066 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -270,12 +270,7 @@ struct Crate {
}
impl Crate {
- fn is_local(&self, build: &Build) -> bool {
- self.path.starts_with(&build.config.src)
- }
-
fn local_path(&self, build: &Build) -> PathBuf {
- assert!(self.is_local(build));
self.path.strip_prefix(&build.config.src).unwrap().into()
}
}
@@ -1079,17 +1074,29 @@ impl Build {
}
}
+ /// Returns a Vec of all the dependencies of the given root crate,
+ /// including transitive dependencies and the root itself. Only includes
+ /// "local" crates (those in the local source tree, not from a registry).
fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
let mut ret = Vec::new();
let mut list = vec![INTERNER.intern_str(root)];
let mut visited = HashSet::new();
while let Some(krate) = list.pop() {
let krate = &self.crates[&krate];
- if krate.is_local(self) {
- ret.push(krate);
- }
+ ret.push(krate);
for dep in &krate.deps {
- if visited.insert(dep) && dep != "build_helper" {
+ // Don't include optional deps if their features are not
+ // enabled. Ideally this would be computed from `cargo
+ // metadata --features …`, but that is somewhat slow. Just
+ // skip `build_helper` since there aren't any operations we
+ // want to perform on it. In the future, we may want to
+ // consider just filtering all build and dev dependencies in
+ // metadata::build.
+ if visited.insert(dep)
+ && dep != "build_helper"
+ && (dep != "profiler_builtins" || self.config.profiler)
+ && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
+ {
list.push(*dep);
}
}
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index 185f0ddb831e7..a38391c7b88f2 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -1,5 +1,3 @@
-use std::collections::HashMap;
-use std::collections::HashSet;
use std::path::PathBuf;
use std::process::Command;
@@ -12,7 +10,6 @@ use crate::{Build, Crate};
#[derive(Deserialize)]
struct Output {
packages: Vec,
- resolve: Resolve,
}
#[derive(Deserialize)]
@@ -21,38 +18,25 @@ struct Package {
name: String,
source: Option,
manifest_path: String,
+ dependencies: Vec,
}
#[derive(Deserialize)]
-struct Resolve {
- nodes: Vec,
-}
-
-#[derive(Deserialize)]
-struct ResolveNode {
- id: String,
- dependencies: Vec,
+struct Dependency {
+ name: String,
+ source: Option,
}
pub fn build(build: &mut Build) {
// Run `cargo metadata` to figure out what crates we're testing.
- let features: Vec<_> = build
- .std_features()
- .split_whitespace()
- .map(|f| format!("test/{}", f))
- .chain(build.rustc_features().split_whitespace().map(|f| format!("rustc-main/{}", f)))
- .collect();
let mut cargo = Command::new(&build.initial_cargo);
cargo
.arg("metadata")
.arg("--format-version")
.arg("1")
- .arg("--features")
- .arg(features.join(","))
- .arg("-Zpackage-features")
+ .arg("--no-deps")
.arg("--manifest-path")
- .arg(build.src.join("Cargo.toml"))
- .env("RUSTC_BOOTSTRAP", "1");
+ .arg(build.src.join("Cargo.toml"));
let output = output(&mut cargo);
let output: Output = serde_json::from_str(&output).unwrap();
for package in output.packages {
@@ -60,26 +44,13 @@ pub fn build(build: &mut Build) {
let name = INTERNER.intern_string(package.name);
let mut path = PathBuf::from(package.manifest_path);
path.pop();
- build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path });
- }
- }
-
- let id2name: HashMap<_, _> =
- build.crates.iter().map(|(name, krate)| (krate.id.clone(), name.clone())).collect();
-
- for node in output.resolve.nodes {
- let name = match id2name.get(&node.id) {
- Some(name) => name,
- None => continue,
- };
-
- let krate = build.crates.get_mut(name).unwrap();
- for dep in node.dependencies.iter() {
- let dep = match id2name.get(dep) {
- Some(dep) => dep,
- None => continue,
- };
- krate.deps.insert(*dep);
+ let deps = package
+ .dependencies
+ .into_iter()
+ .filter(|dep| dep.source.is_none())
+ .map(|dep| INTERNER.intern_string(dep.name))
+ .collect();
+ build.crates.insert(name, Crate { name, id: package.id, deps, path });
}
}
}
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 8659acf1cc5a5..c1d0316920be7 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1651,12 +1651,8 @@ impl Step for Crate {
type Output = ();
const DEFAULT: bool = true;
- fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
- let builder = run.builder;
- for krate in run.builder.in_tree_crates("test") {
- run = run.path(krate.local_path(&builder).to_str().unwrap());
- }
- run
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.krate("test")
}
fn make_run(run: RunConfig<'_>) {
From 5393a2995bcea9a927c23d88a921c55bea886771 Mon Sep 17 00:00:00 2001
From: Gary Guo
Date: Sat, 16 May 2020 18:44:31 +0100
Subject: [PATCH 030/123] Move convert_place_derefs_to_mutable out from
check/method/confirm.rs
This can live inside FnCtxt rather than ConfirmContext, and would be
useful for other operations as well.
---
src/librustc_typeck/check/method/confirm.rs | 151 +------------------
src/librustc_typeck/check/mod.rs | 1 +
src/librustc_typeck/check/reconciliation.rs | 153 ++++++++++++++++++++
3 files changed, 157 insertions(+), 148 deletions(-)
create mode 100644 src/librustc_typeck/check/reconciliation.rs
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 007794ce1b7ff..867dacede6e44 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -1,12 +1,12 @@
use super::{probe, MethodCallee};
use crate::astconv::AstConv;
-use crate::check::{callee, FnCtxt, Needs, PlaceOp};
+use crate::check::{callee, FnCtxt, Needs};
use crate::hir::def_id::DefId;
use crate::hir::GenericArg;
use rustc_hir as hir;
use rustc_infer::infer::{self, InferOk};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{Subst, SubstsRef};
@@ -121,7 +121,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig };
if let Some(hir::Mutability::Mut) = pick.autoref {
- self.convert_place_derefs_to_mutable();
+ self.convert_place_derefs_to_mutable(self.self_expr);
}
ConfirmResult { callee, illegal_sized_bound }
@@ -416,151 +416,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation);
}
- ///////////////////////////////////////////////////////////////////////////
- // RECONCILIATION
-
- /// When we select a method with a mutable autoref, we have to go convert any
- /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
- /// respectively.
- fn convert_place_derefs_to_mutable(&self) {
- // Gather up expressions we want to munge.
- let mut exprs = vec![self.self_expr];
-
- loop {
- match exprs.last().unwrap().kind {
- hir::ExprKind::Field(ref expr, _)
- | hir::ExprKind::Index(ref expr, _)
- | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
- _ => break,
- }
- }
-
- debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
-
- // Fix up autoderefs and derefs.
- for (i, &expr) in exprs.iter().rev().enumerate() {
- debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
-
- // Fix up the autoderefs. Autorefs can only occur immediately preceding
- // overloaded place ops, and will be fixed by them in order to get
- // the correct region.
- let mut source = self.node_ty(expr.hir_id);
- // Do not mutate adjustments in place, but rather take them,
- // and replace them after mutating them, to avoid having the
- // tables borrowed during (`deref_mut`) method resolution.
- let previous_adjustments =
- self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
- if let Some(mut adjustments) = previous_adjustments {
- let needs = Needs::MutPlace;
- for adjustment in &mut adjustments {
- if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
- if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) {
- let method = self.register_infer_ok_obligations(ok);
- if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
- *deref = OverloadedDeref { region, mutbl };
- }
- }
- }
- source = adjustment.target;
- }
- self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
- }
-
- match expr.kind {
- hir::ExprKind::Index(ref base_expr, ref index_expr) => {
- // We need to get the final type in case dereferences were needed for the trait
- // to apply (#72002).
- let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
- self.convert_place_op_to_mutable(
- PlaceOp::Index,
- expr,
- base_expr,
- &[index_expr_ty],
- );
- }
- hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
- self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
- }
- _ => {}
- }
- }
- }
-
- fn convert_place_op_to_mutable(
- &self,
- op: PlaceOp,
- expr: &hir::Expr<'_>,
- base_expr: &hir::Expr<'_>,
- arg_tys: &[Ty<'tcx>],
- ) {
- debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
- if !self.tables.borrow().is_method_call(expr) {
- debug!("convert_place_op_to_mutable - builtin, nothing to do");
- return;
- }
-
- let base_ty = self
- .tables
- .borrow()
- .expr_adjustments(base_expr)
- .last()
- .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target);
- let base_ty = self.resolve_vars_if_possible(&base_ty);
-
- // Need to deref because overloaded place ops take self by-reference.
- let base_ty =
- base_ty.builtin_deref(false).expect("place op takes something that is not a ref").ty;
-
- let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op);
- let method = match method {
- Some(ok) => self.register_infer_ok_obligations(ok),
- None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed"),
- };
- debug!("convert_place_op_to_mutable: method={:?}", method);
- self.write_method_call(expr.hir_id, method);
-
- let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind {
- (r, mutbl)
- } else {
- span_bug!(expr.span, "input to place op is not a ref?");
- };
-
- // Convert the autoref in the base expr to mutable with the correct
- // region and mutability.
- let base_expr_ty = self.node_ty(base_expr.hir_id);
- if let Some(adjustments) =
- self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
- {
- let mut source = base_expr_ty;
- for adjustment in &mut adjustments[..] {
- if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
- debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded operators.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
- adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
- adjustment.target =
- self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
- }
- source = adjustment.target;
- }
-
- // If we have an autoref followed by unsizing at the end, fix the unsize target.
-
- if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
- adjustments[..]
- {
- *target = method.sig.inputs()[0];
- }
- }
- }
-
///////////////////////////////////////////////////////////////////////////
// MISCELLANY
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fabedc3800ae4..1e4085f026768 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -79,6 +79,7 @@ pub mod intrinsic;
pub mod method;
mod op;
mod pat;
+mod reconciliation;
mod regionck;
mod upvar;
mod wfcheck;
diff --git a/src/librustc_typeck/check/reconciliation.rs b/src/librustc_typeck/check/reconciliation.rs
new file mode 100644
index 0000000000000..b05155ae2aedd
--- /dev/null
+++ b/src/librustc_typeck/check/reconciliation.rs
@@ -0,0 +1,153 @@
+use crate::check::{FnCtxt, Needs, PlaceOp};
+use rustc_hir as hir;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::{self, Ty};
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
+ /// into `DerefMut` and `IndexMut` respectively.
+ ///
+ /// This is a second pass of typechecking derefs/indices. We need this we do not
+ /// always know whether a place needs to be mutable or not in the first pass.
+ /// This happens whether there is an implicit mutable reborrow, e.g. when the type
+ /// is used as the receiver of a method call.
+ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
+ // Gather up expressions we want to munge.
+ let mut exprs = vec![expr];
+
+ loop {
+ match exprs.last().unwrap().kind {
+ hir::ExprKind::Field(ref expr, _)
+ | hir::ExprKind::Index(ref expr, _)
+ | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
+ _ => break,
+ }
+ }
+
+ debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
+
+ // Fix up autoderefs and derefs.
+ for (i, &expr) in exprs.iter().rev().enumerate() {
+ debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
+
+ // Fix up the autoderefs. Autorefs can only occur immediately preceding
+ // overloaded place ops, and will be fixed by them in order to get
+ // the correct region.
+ let mut source = self.node_ty(expr.hir_id);
+ // Do not mutate adjustments in place, but rather take them,
+ // and replace them after mutating them, to avoid having the
+ // tables borrowed during (`deref_mut`) method resolution.
+ let previous_adjustments =
+ self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
+ if let Some(mut adjustments) = previous_adjustments {
+ let needs = Needs::MutPlace;
+ for adjustment in &mut adjustments {
+ if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
+ if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) {
+ let method = self.register_infer_ok_obligations(ok);
+ if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
+ *deref = OverloadedDeref { region, mutbl };
+ }
+ }
+ }
+ source = adjustment.target;
+ }
+ self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
+ }
+
+ match expr.kind {
+ hir::ExprKind::Index(ref base_expr, ref index_expr) => {
+ // We need to get the final type in case dereferences were needed for the trait
+ // to apply (#72002).
+ let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
+ self.convert_place_op_to_mutable(
+ PlaceOp::Index,
+ expr,
+ base_expr,
+ &[index_expr_ty],
+ );
+ }
+ hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
+ self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
+ }
+ _ => {}
+ }
+ }
+ }
+
+ fn convert_place_op_to_mutable(
+ &self,
+ op: PlaceOp,
+ expr: &hir::Expr<'_>,
+ base_expr: &hir::Expr<'_>,
+ arg_tys: &[Ty<'tcx>],
+ ) {
+ debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
+ if !self.tables.borrow().is_method_call(expr) {
+ debug!("convert_place_op_to_mutable - builtin, nothing to do");
+ return;
+ }
+
+ let base_ty = self
+ .tables
+ .borrow()
+ .expr_adjustments(base_expr)
+ .last()
+ .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target);
+ let base_ty = self.resolve_vars_if_possible(&base_ty);
+
+ // Need to deref because overloaded place ops take self by-reference.
+ let base_ty =
+ base_ty.builtin_deref(false).expect("place op takes something that is not a ref").ty;
+
+ let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op);
+ let method = match method {
+ Some(ok) => self.register_infer_ok_obligations(ok),
+ None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed"),
+ };
+ debug!("convert_place_op_to_mutable: method={:?}", method);
+ self.write_method_call(expr.hir_id, method);
+
+ let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind {
+ (r, mutbl)
+ } else {
+ span_bug!(expr.span, "input to place op is not a ref?");
+ };
+
+ // Convert the autoref in the base expr to mutable with the correct
+ // region and mutability.
+ let base_expr_ty = self.node_ty(base_expr.hir_id);
+ if let Some(adjustments) =
+ self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
+ {
+ let mut source = base_expr_ty;
+ for adjustment in &mut adjustments[..] {
+ if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
+ debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
+ let mutbl = match mutbl {
+ hir::Mutability::Not => AutoBorrowMutability::Not,
+ hir::Mutability::Mut => AutoBorrowMutability::Mut {
+ // For initial two-phase borrow
+ // deployment, conservatively omit
+ // overloaded operators.
+ allow_two_phase_borrow: AllowTwoPhase::No,
+ },
+ };
+ adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
+ adjustment.target =
+ self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+ }
+ source = adjustment.target;
+ }
+
+ // If we have an autoref followed by unsizing at the end, fix the unsize target.
+
+ if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
+ adjustments[..]
+ {
+ *target = method.sig.inputs()[0];
+ }
+ }
+ }
+}
From fb0793c610d99857820721f58456920e9e0bc240 Mon Sep 17 00:00:00 2001
From: Gary Guo
Date: Mon, 15 Jun 2020 00:57:21 +0100
Subject: [PATCH 031/123] Add some comments to librustc_typeck/check/callee.rs
---
src/librustc_typeck/check/callee.rs | 37 +++++++++++++++++------------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index aa316105f7f11..f86b7f07b7fc4 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -220,21 +220,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let method = self.register_infer_ok_obligations(ok);
let mut autoref = None;
if borrow {
- if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded function call ops.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
- autoref = Some(Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
- target: method.sig.inputs()[0],
- });
- }
+ // Check for &self vs &mut self in the method signature. Since this is either
+ // the Fn or FnMut trait, it should be one of those.
+ let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind
+ {
+ (r, mutbl)
+ } else {
+ span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
+ };
+
+ let mutbl = match mutbl {
+ hir::Mutability::Not => AutoBorrowMutability::Not,
+ hir::Mutability::Mut => AutoBorrowMutability::Mut {
+ // For initial two-phase borrow
+ // deployment, conservatively omit
+ // overloaded function call ops.
+ allow_two_phase_borrow: AllowTwoPhase::No,
+ },
+ };
+ autoref = Some(Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+ target: method.sig.inputs()[0],
+ });
}
return Some((autoref, method));
}
From c2b920fab328201a2b5507b9a484c8c09752af93 Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Sun, 14 Jun 2020 16:58:45 -0700
Subject: [PATCH 032/123] Show suite paths (`src/test/ui/...`) in help output.
---
src/bootstrap/builder.rs | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 345af600c2adb..545ad64ba2cf6 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -489,13 +489,19 @@ impl<'a> Builder<'a> {
should_run = (desc.should_run)(should_run);
}
let mut help = String::from("Available paths:\n");
+ let mut add_path = |path: &Path| {
+ help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display()));
+ };
for pathset in should_run.paths {
- if let PathSet::Set(set) = pathset {
- set.iter().for_each(|path| {
- help.push_str(
- format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(),
- )
- })
+ match pathset {
+ PathSet::Set(set) => {
+ for path in set {
+ add_path(&path);
+ }
+ }
+ PathSet::Suite(path) => {
+ add_path(&path.join("..."));
+ }
}
}
Some(help)
From f17fd7b0e692c59075db58ac2e7ca3ac2d5e19bd Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Sun, 14 Jun 2020 17:00:34 -0700
Subject: [PATCH 033/123] Add some doc comments regarding PathSet.
---
src/bootstrap/builder.rs | 28 +++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 545ad64ba2cf6..c2f748f161f18 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -97,9 +97,21 @@ struct StepDescription {
name: &'static str,
}
+/// Collection of paths used to match a task rule.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub enum PathSet {
+ /// A collection of individual paths.
+ ///
+ /// These are generally matched as a path suffix. For example, a
+ /// command-line value of `libstd` will match if `src/libstd` is in the
+ /// set.
Set(BTreeSet),
+ /// A "suite" of paths.
+ ///
+ /// These can match as a path suffix (like `Set`), or as a prefix. For
+ /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs`
+ /// will match `src/test/ui`. A command-line value of `ui` would also
+ /// match `src/test/ui`.
Suite(PathBuf),
}
@@ -249,9 +261,15 @@ impl<'a> ShouldRun<'a> {
self
}
- // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
- // ever be used, but as we transition to having all rules properly handle passing krate(...) by
- // actually doing something different for every crate passed.
+ /// Indicates it should run if the command-line selects the given crate or
+ /// any of its (local) dependencies.
+ ///
+ /// Compared to `krate`, this treats the dependencies as aliases for the
+ /// same job. Generally it is preferred to use `krate`, and treat each
+ /// individual path separately. For example `./x.py test src/liballoc`
+ /// (which uses `krate`) will test just `liballoc`. However, `./x.py check
+ /// src/liballoc` (which uses `all_krates`) will check all of `libtest`.
+ /// `all_krates` should probably be removed at some point.
pub fn all_krates(mut self, name: &str) -> Self {
let mut set = BTreeSet::new();
for krate in self.builder.in_tree_crates(name) {
@@ -262,6 +280,10 @@ impl<'a> ShouldRun<'a> {
self
}
+ /// Indicates it should run if the command-line selects the given crate or
+ /// any of its (local) dependencies.
+ ///
+ /// `make_run` will be called separately for each matching command-line path.
pub fn krate(mut self, name: &str) -> Self {
for krate in self.builder.in_tree_crates(name) {
let path = krate.local_path(self.builder);
From 8121d2e0576e74b23f0019e857b1088197ef8c04 Mon Sep 17 00:00:00 2001
From: Gary Guo
Date: Mon, 15 Jun 2020 00:58:37 +0100
Subject: [PATCH 034/123] Fix up autoderef when performing mutable auto borrow
---
src/librustc_typeck/check/method/confirm.rs | 5 -----
src/librustc_typeck/check/mod.rs | 15 +++++++++++++++
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 867dacede6e44..c0f1f356ef372 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -119,11 +119,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// Create the final `MethodCallee`.
let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig };
-
- if let Some(hir::Mutability::Mut) = pick.autoref {
- self.convert_place_derefs_to_mutable(self.self_expr);
- }
-
ConfirmResult { callee, illegal_sized_bound }
}
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1e4085f026768..82523f843aef9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3183,6 +3183,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
+ let autoborrow_mut = adj.iter().any(|adj| {
+ matches!(adj, &Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+ ..
+ })
+ });
+
match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) {
Entry::Vacant(entry) => {
entry.insert(adj);
@@ -3212,6 +3219,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
*entry.get_mut() = adj;
}
}
+
+ // When there is an auto mutable borrow, it is equivalent to `&mut expr`,
+ // thus `expr` is ought to be typechecked with needs = [`Needs::MutPlace`].
+ // However in many cases it might not be checked this way originally, e.g.
+ // the receiver of a method call. We need to fix them up.
+ if autoborrow_mut {
+ self.convert_place_derefs_to_mutable(expr);
+ }
}
/// Basically whenever we are converting from a type scheme into
From 4710f85882c08594a900b09c13fbe51ca207daec Mon Sep 17 00:00:00 2001
From: Gary Guo
Date: Mon, 15 Jun 2020 00:59:03 +0100
Subject: [PATCH 035/123] Add ui tests for issue 68590 and 72225
---
.../issue-68590-reborrow-through-derefmut.rs | 25 +++++++++++++++++++
...issue-72225-call-fnmut-through-derefmut.rs | 21 ++++++++++++++++
2 files changed, 46 insertions(+)
create mode 100644 src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs
create mode 100644 src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs
diff --git a/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs b/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs
new file mode 100644
index 0000000000000..e4436260e70a0
--- /dev/null
+++ b/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs
@@ -0,0 +1,25 @@
+// check-pass
+
+// rust-lang/rust#68590: confusing diagnostics when reborrowing through DerefMut.
+
+use std::cell::RefCell;
+
+struct A;
+
+struct S<'a> {
+ a: &'a mut A,
+}
+
+fn take_a(_: &mut A) {}
+
+fn test<'a>(s: &RefCell>) {
+ let mut guard = s.borrow_mut();
+ take_a(guard.a);
+ let _s2 = S { a: guard.a };
+}
+
+fn main() {
+ let a = &mut A;
+ let s = RefCell::new(S { a });
+ test(&s);
+}
diff --git a/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs b/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs
new file mode 100644
index 0000000000000..3ea05389f04a0
--- /dev/null
+++ b/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+// rust-lang/rust#72225: confusing diagnostics when calling FnMut through DerefMut.
+
+use std::cell::RefCell;
+
+struct S {
+ f: Box
+}
+
+fn test(s: &RefCell) {
+ let mut guard = s.borrow_mut();
+ (guard.f)();
+}
+
+fn main() {
+ let s = RefCell::new(S {
+ f: Box::new(|| ())
+ });
+ test(&s);
+}
From 0906066ae7d8a5e217e8cbf7f17de78a00d4ed83 Mon Sep 17 00:00:00 2001
From: Erik Desjardins
Date: Mon, 15 Jun 2020 00:50:56 -0400
Subject: [PATCH 036/123] Test that bounds checks are elided when slice len is
checked up-front
---
src/test/codegen/issue-69101-bounds-check.rs | 26 ++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 src/test/codegen/issue-69101-bounds-check.rs
diff --git a/src/test/codegen/issue-69101-bounds-check.rs b/src/test/codegen/issue-69101-bounds-check.rs
new file mode 100644
index 0000000000000..cdbe51da03cc2
--- /dev/null
+++ b/src/test/codegen/issue-69101-bounds-check.rs
@@ -0,0 +1,26 @@
+// no-system-llvm
+// compile-flags: -O
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @already_sliced_no_bounds_check
+#[no_mangle]
+pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+ // CHECK: slice_index_len_fail
+ // CHECK-NOT: panic_bounds_check
+ let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
+ for i in 0..1024 {
+ c[i] = a[i] ^ b[i];
+ }
+}
+
+// make sure we're checking for the right thing: there can be a panic if the slice is too small
+// CHECK-LABEL: @already_sliced_bounds_check
+#[no_mangle]
+pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+ // CHECK: slice_index_len_fail
+ // CHECK: panic_bounds_check
+ let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
+ for i in 0..1024 {
+ c[i] = a[i] ^ b[i];
+ }
+}
From f62903b74a8630fa62e721f69e6621d1d441e7f1 Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Fri, 5 Jun 2020 16:47:37 +0100
Subject: [PATCH 037/123] Export `#[inline] #[no_mangle]` fns in cdylibs and
staticlibs
---
src/librustc_codegen_ssa/back/symbol_export.rs | 9 +++++----
src/librustc_middle/mir/mono.rs | 1 +
src/librustc_middle/query/mod.rs | 4 ++++
src/librustc_typeck/collect.rs | 12 ++++++++++++
src/test/codegen/cdylib-external-no-mangle-fns.rs | 13 +++++++++++++
.../codegen/staticlib-external-no-mangle-fns.rs | 13 +++++++++++++
6 files changed, 48 insertions(+), 4 deletions(-)
create mode 100644 src/test/codegen/cdylib-external-no-mangle-fns.rs
create mode 100644 src/test/codegen/staticlib-external-no-mangle-fns.rs
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index 970d13b30c04e..bf8693f3547a4 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -89,10 +89,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
let def_id = tcx.hir().local_def_id(hir_id);
let generics = tcx.generics_of(def_id);
- if !generics.requires_monomorphization(tcx) &&
- // Functions marked with #[inline] are only ever codegened
- // with "internal" linkage and are never exported.
- !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
+ if !generics.requires_monomorphization(tcx)
+ && (!Instance::mono(tcx, def_id.to_def_id())
+ .def
+ .generates_cgu_internal_copy(tcx)
+ || tcx.inline_exportable(def_id.to_def_id()))
{
Some(def_id)
} else {
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index c889dbc0a4498..d8dcf0dea8a5f 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -95,6 +95,7 @@ impl<'tcx> MonoItem<'tcx> {
// linkage, then we'll be creating a globally shared version.
if self.explicit_linkage(tcx).is_some()
|| !instance.def.generates_cgu_internal_copy(tcx)
+ || tcx.inline_exportable(instance.def_id())
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
{
return InstantiationMode::GloballyShared { may_conflict: false };
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index be15e6c576f69..20487fdb6696d 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -697,6 +697,10 @@ rustc_queries! {
storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { true }
}
+
+ query inline_exportable(def_id: DefId) -> bool {
+ desc { |tcx| "computing whether `{}` should be explicitly exported", tcx.def_path_str(def_id) }
+ }
}
Other {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1d59d749634ee..08a6330e718e6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -40,6 +40,7 @@ use rustc_middle::ty::util::Discr;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
+use rustc_session::config::CrateType;
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -79,6 +80,7 @@ pub fn provide(providers: &mut Providers<'_>) {
static_mutability,
generator_kind,
codegen_fn_attrs,
+ inline_exportable,
collect_mod_item_types,
..*providers
};
@@ -2599,6 +2601,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs
}
+fn inline_exportable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ // Functions marked with #[inline] are only ever codegened
+ // with "internal" linkage and are never exported unless we're
+ // building a `staticlib` or `cdylib` and they are marked
+ // `#[no_mangle]`.
+ tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_MANGLE)
+ && (tcx.sess.crate_types().contains(&CrateType::Cdylib)
+ || tcx.sess.crate_types().contains(&CrateType::Staticlib))
+}
+
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
diff --git a/src/test/codegen/cdylib-external-no-mangle-fns.rs b/src/test/codegen/cdylib-external-no-mangle-fns.rs
new file mode 100644
index 0000000000000..827de7e5c11d9
--- /dev/null
+++ b/src/test/codegen/cdylib-external-no-mangle-fns.rs
@@ -0,0 +1,13 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "cdylib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {
+ // side effect to keep `a` around
+ unsafe {
+ core::ptr::read_volatile(&42);
+ }
+}
diff --git a/src/test/codegen/staticlib-external-no-mangle-fns.rs b/src/test/codegen/staticlib-external-no-mangle-fns.rs
new file mode 100644
index 0000000000000..0b4a37febb209
--- /dev/null
+++ b/src/test/codegen/staticlib-external-no-mangle-fns.rs
@@ -0,0 +1,13 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "staticlib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {
+ // side effect to keep `a` around
+ unsafe {
+ core::ptr::read_volatile(&42);
+ }
+}
From 6b7cacb2c99567a76cf0d5ce6833a129c8bb8814 Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Mon, 8 Jun 2020 09:37:11 +0100
Subject: [PATCH 038/123] Export all fns with extern indicator
---
.../back/symbol_export.rs | 9 ++++----
src/librustc_middle/mir/mono.rs | 12 ++++++----
src/librustc_middle/query/mod.rs | 4 ----
src/librustc_typeck/collect.rs | 12 ----------
.../codegen/cdylib-external-inline-fns.rs | 23 +++++++++++++++++++
.../codegen/cdylib-external-no-mangle-fns.rs | 13 -----------
src/test/codegen/export-no-mangle.rs | 5 ++++
src/test/codegen/external-no-mangle-fns.rs | 10 ++++++++
.../codegen/staticlib-external-inline-fns.rs | 23 +++++++++++++++++++
.../staticlib-external-no-mangle-fns.rs | 13 -----------
10 files changed, 74 insertions(+), 50 deletions(-)
create mode 100644 src/test/codegen/cdylib-external-inline-fns.rs
delete mode 100644 src/test/codegen/cdylib-external-no-mangle-fns.rs
create mode 100644 src/test/codegen/staticlib-external-inline-fns.rs
delete mode 100644 src/test/codegen/staticlib-external-no-mangle-fns.rs
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index bf8693f3547a4..98f7da8361cc4 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -90,10 +90,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
let def_id = tcx.hir().local_def_id(hir_id);
let generics = tcx.generics_of(def_id);
if !generics.requires_monomorphization(tcx)
- && (!Instance::mono(tcx, def_id.to_def_id())
- .def
- .generates_cgu_internal_copy(tcx)
- || tcx.inline_exportable(def_id.to_def_id()))
+ // Functions marked with #[inline] are codegened with "internal"
+ // linkage and are not exported unless marked with an extern
+ // inidicator
+ && (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
+ || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator())
{
Some(def_id)
} else {
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index d8dcf0dea8a5f..886690da212d3 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -92,10 +92,10 @@ impl<'tcx> MonoItem<'tcx> {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
// If this function isn't inlined or otherwise has explicit
- // linkage, then we'll be creating a globally shared version.
+ // linkage or an extern indicator, then we'll be creating a
+ // globally shared version.
if self.explicit_linkage(tcx).is_some()
|| !instance.def.generates_cgu_internal_copy(tcx)
- || tcx.inline_exportable(instance.def_id())
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
{
return InstantiationMode::GloballyShared { may_conflict: false };
@@ -103,8 +103,12 @@ impl<'tcx> MonoItem<'tcx> {
// At this point we don't have explicit linkage and we're an
// inlined function. If we're inlining into all CGUs then we'll
- // be creating a local copy per CGU
- if generate_cgu_internal_copies {
+ // be creating a local copy per CGU. We need to watch out here
+ // for an extern indicator as we don't want to optimise away
+ // inlined functions that should be exported.
+ if generate_cgu_internal_copies
+ && !tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
+ {
return InstantiationMode::LocalCopy;
}
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index 20487fdb6696d..be15e6c576f69 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -697,10 +697,6 @@ rustc_queries! {
storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { true }
}
-
- query inline_exportable(def_id: DefId) -> bool {
- desc { |tcx| "computing whether `{}` should be explicitly exported", tcx.def_path_str(def_id) }
- }
}
Other {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 08a6330e718e6..1d59d749634ee 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -40,7 +40,6 @@ use rustc_middle::ty::util::Discr;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
-use rustc_session::config::CrateType;
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -80,7 +79,6 @@ pub fn provide(providers: &mut Providers<'_>) {
static_mutability,
generator_kind,
codegen_fn_attrs,
- inline_exportable,
collect_mod_item_types,
..*providers
};
@@ -2601,16 +2599,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs
}
-fn inline_exportable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- // Functions marked with #[inline] are only ever codegened
- // with "internal" linkage and are never exported unless we're
- // building a `staticlib` or `cdylib` and they are marked
- // `#[no_mangle]`.
- tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_MANGLE)
- && (tcx.sess.crate_types().contains(&CrateType::Cdylib)
- || tcx.sess.crate_types().contains(&CrateType::Staticlib))
-}
-
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
diff --git a/src/test/codegen/cdylib-external-inline-fns.rs b/src/test/codegen/cdylib-external-inline-fns.rs
new file mode 100644
index 0000000000000..58f806b5a1f34
--- /dev/null
+++ b/src/test/codegen/cdylib-external-inline-fns.rs
@@ -0,0 +1,23 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "cdylib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
diff --git a/src/test/codegen/cdylib-external-no-mangle-fns.rs b/src/test/codegen/cdylib-external-no-mangle-fns.rs
deleted file mode 100644
index 827de7e5c11d9..0000000000000
--- a/src/test/codegen/cdylib-external-no-mangle-fns.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-
-#![crate_type = "cdylib"]
-
-// CHECK: define void @a()
-#[no_mangle]
-#[inline]
-pub extern "C" fn a() {
- // side effect to keep `a` around
- unsafe {
- core::ptr::read_volatile(&42);
- }
-}
diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs
index 78d41e4be0ae9..793636bb1b030 100644
--- a/src/test/codegen/export-no-mangle.rs
+++ b/src/test/codegen/export-no-mangle.rs
@@ -18,4 +18,9 @@ mod private {
// CHECK: void @bar()
#[export_name = "bar"]
extern fn bar() {}
+
+ // CHECK: void @baz()
+ #[export_name = "baz"]
+ #[inline]
+ extern fn baz() {}
}
diff --git a/src/test/codegen/external-no-mangle-fns.rs b/src/test/codegen/external-no-mangle-fns.rs
index 902882144996f..aefa9ce21c3ee 100644
--- a/src/test/codegen/external-no-mangle-fns.rs
+++ b/src/test/codegen/external-no-mangle-fns.rs
@@ -53,3 +53,13 @@ fn x() {
core::ptr::read_volatile(&42);
}
}
+
+// CHECK: define void @i()
+#[no_mangle]
+#[inline]
+fn i() {}
+
+// CHECK: define void @j()
+#[no_mangle]
+#[inline]
+pub fn j() {}
diff --git a/src/test/codegen/staticlib-external-inline-fns.rs b/src/test/codegen/staticlib-external-inline-fns.rs
new file mode 100644
index 0000000000000..8f55a5303311c
--- /dev/null
+++ b/src/test/codegen/staticlib-external-inline-fns.rs
@@ -0,0 +1,23 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "staticlib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
diff --git a/src/test/codegen/staticlib-external-no-mangle-fns.rs b/src/test/codegen/staticlib-external-no-mangle-fns.rs
deleted file mode 100644
index 0b4a37febb209..0000000000000
--- a/src/test/codegen/staticlib-external-no-mangle-fns.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-
-#![crate_type = "staticlib"]
-
-// CHECK: define void @a()
-#[no_mangle]
-#[inline]
-pub extern "C" fn a() {
- // side effect to keep `a` around
- unsafe {
- core::ptr::read_volatile(&42);
- }
-}
From d23bedd13d70597a7db70ef5ea549fc7a4063d10 Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Mon, 8 Jun 2020 09:54:33 +0100
Subject: [PATCH 039/123] Fix whitespace
---
src/test/codegen/export-no-mangle.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs
index 793636bb1b030..a52fac37021dd 100644
--- a/src/test/codegen/export-no-mangle.rs
+++ b/src/test/codegen/export-no-mangle.rs
@@ -18,7 +18,7 @@ mod private {
// CHECK: void @bar()
#[export_name = "bar"]
extern fn bar() {}
-
+
// CHECK: void @baz()
#[export_name = "baz"]
#[inline]
From ee810a75e41368387918759ed191657f05650f05 Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Tue, 9 Jun 2020 15:49:59 +0100
Subject: [PATCH 040/123] Fix exports with `#[inline(always)]`
---
src/librustc_middle/mir/mono.rs | 15 +++++--------
.../codegen/cdylib-external-inline-fns.rs | 20 ++++++++++++++++++
src/test/codegen/export-no-mangle.rs | 21 ++++++++++++-------
src/test/codegen/external-no-mangle-fns.rs | 10 +++++++++
.../codegen/staticlib-external-inline-fns.rs | 20 ++++++++++++++++++
5 files changed, 68 insertions(+), 18 deletions(-)
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index 886690da212d3..24d324ff09c4c 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -91,10 +91,9 @@ impl<'tcx> MonoItem<'tcx> {
match *self {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
- // If this function isn't inlined or otherwise has explicit
- // linkage or an extern indicator, then we'll be creating a
- // globally shared version.
- if self.explicit_linkage(tcx).is_some()
+ // If this function isn't inlined or otherwise has an extern
+ // indicator, then we'll be creating a globally shared version.
+ if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
|| !instance.def.generates_cgu_internal_copy(tcx)
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
{
@@ -103,12 +102,8 @@ impl<'tcx> MonoItem<'tcx> {
// At this point we don't have explicit linkage and we're an
// inlined function. If we're inlining into all CGUs then we'll
- // be creating a local copy per CGU. We need to watch out here
- // for an extern indicator as we don't want to optimise away
- // inlined functions that should be exported.
- if generate_cgu_internal_copies
- && !tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
- {
+ // be creating a local copy per CGU.
+ if generate_cgu_internal_copies {
return InstantiationMode::LocalCopy;
}
diff --git a/src/test/codegen/cdylib-external-inline-fns.rs b/src/test/codegen/cdylib-external-inline-fns.rs
index 58f806b5a1f34..519be6b6a99a4 100644
--- a/src/test/codegen/cdylib-external-inline-fns.rs
+++ b/src/test/codegen/cdylib-external-inline-fns.rs
@@ -21,3 +21,23 @@ extern "C" fn c() {}
#[export_name = "d"]
#[inline]
extern "C" fn d() {}
+
+// CHECK: define void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs
index a52fac37021dd..11427ae38822f 100644
--- a/src/test/codegen/export-no-mangle.rs
+++ b/src/test/codegen/export-no-mangle.rs
@@ -11,16 +11,21 @@ mod private {
#[export_name = "BAR"]
static BAR: u32 = 3;
- // CHECK: void @foo()
+ // CHECK: void @a()
#[no_mangle]
- pub extern fn foo() {}
+ pub extern fn a() {}
- // CHECK: void @bar()
- #[export_name = "bar"]
- extern fn bar() {}
+ // CHECK: void @b()
+ #[export_name = "b"]
+ extern fn b() {}
- // CHECK: void @baz()
- #[export_name = "baz"]
+ // CHECK: void @c()
+ #[export_name = "c"]
#[inline]
- extern fn baz() {}
+ extern fn c() {}
+
+ // CHECK: void @d()
+ #[export_name = "d"]
+ #[inline(always)]
+ extern fn d() {}
}
diff --git a/src/test/codegen/external-no-mangle-fns.rs b/src/test/codegen/external-no-mangle-fns.rs
index aefa9ce21c3ee..41820b057f1ef 100644
--- a/src/test/codegen/external-no-mangle-fns.rs
+++ b/src/test/codegen/external-no-mangle-fns.rs
@@ -63,3 +63,13 @@ fn i() {}
#[no_mangle]
#[inline]
pub fn j() {}
+
+// CHECK: define void @k()
+#[no_mangle]
+#[inline(always)]
+fn k() {}
+
+// CHECK: define void @l()
+#[no_mangle]
+#[inline(always)]
+pub fn l() {}
diff --git a/src/test/codegen/staticlib-external-inline-fns.rs b/src/test/codegen/staticlib-external-inline-fns.rs
index 8f55a5303311c..8876ab7376afe 100644
--- a/src/test/codegen/staticlib-external-inline-fns.rs
+++ b/src/test/codegen/staticlib-external-inline-fns.rs
@@ -21,3 +21,23 @@ extern "C" fn c() {}
#[export_name = "d"]
#[inline]
extern "C" fn d() {}
+
+// CHECK: define void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
From 11b56fbfb63ef8e2494b8631488e478794c80ed4 Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Tue, 9 Jun 2020 15:54:34 +0100
Subject: [PATCH 041/123] Fix whitespace
---
src/librustc_middle/mir/mono.rs | 2 +-
src/test/codegen/export-no-mangle.rs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index 24d324ff09c4c..f1c1b962ab997 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -102,7 +102,7 @@ impl<'tcx> MonoItem<'tcx> {
// At this point we don't have explicit linkage and we're an
// inlined function. If we're inlining into all CGUs then we'll
- // be creating a local copy per CGU.
+ // be creating a local copy per CGU.
if generate_cgu_internal_copies {
return InstantiationMode::LocalCopy;
}
diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs
index 11427ae38822f..59e97601c838d 100644
--- a/src/test/codegen/export-no-mangle.rs
+++ b/src/test/codegen/export-no-mangle.rs
@@ -23,7 +23,7 @@ mod private {
#[export_name = "c"]
#[inline]
extern fn c() {}
-
+
// CHECK: void @d()
#[export_name = "d"]
#[inline(always)]
From babda9470ea1e5932d238b7f805e76379f01d37c Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Mon, 15 Jun 2020 10:21:19 +0100
Subject: [PATCH 042/123] Fix sanitizer test
---
src/test/codegen/sanitizer-no-sanitize-inlining.rs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/test/codegen/sanitizer-no-sanitize-inlining.rs b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
index d96e76618d325..86e58c3c9bb17 100644
--- a/src/test/codegen/sanitizer-no-sanitize-inlining.rs
+++ b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
@@ -13,7 +13,7 @@
#![feature(no_sanitize)]
// ASAN-LABEL: define void @test
-// ASAN: tail call fastcc void @random_inline
+// ASAN: tail call fastcc
// ASAN: }
//
// LSAN-LABEL: define void @test
@@ -26,7 +26,6 @@ pub fn test(n: &mut u32) {
#[no_sanitize(address)]
#[inline]
-#[no_mangle]
pub fn random_inline(n: &mut u32) {
*n = 42;
}
From e8e0a0e4e220533db31bc6a572ed9f1b99b31289 Mon Sep 17 00:00:00 2001
From: Nathan Corbyn
Date: Mon, 15 Jun 2020 11:12:19 +0100
Subject: [PATCH 043/123] Update sanitizer test
---
src/test/codegen/sanitizer-no-sanitize-inlining.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/test/codegen/sanitizer-no-sanitize-inlining.rs b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
index 86e58c3c9bb17..48231d6f7208d 100644
--- a/src/test/codegen/sanitizer-no-sanitize-inlining.rs
+++ b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
@@ -13,7 +13,7 @@
#![feature(no_sanitize)]
// ASAN-LABEL: define void @test
-// ASAN: tail call fastcc
+// ASAN: call {{.*}} @random_inline
// ASAN: }
//
// LSAN-LABEL: define void @test
@@ -26,6 +26,7 @@ pub fn test(n: &mut u32) {
#[no_sanitize(address)]
#[inline]
+#[no_mangle]
pub fn random_inline(n: &mut u32) {
*n = 42;
}
From d3ca6fd71ed3003e58c6b58d7beb0505d0c8adc3 Mon Sep 17 00:00:00 2001
From: Harald Hoyer
Date: Mon, 15 Jun 2020 13:23:38 +0200
Subject: [PATCH 044/123] Enable static-pie for the x86_64-unknown-linux-musl
target
Fixes: https://github.com/rust-lang/rust/issues/70693
---
.../spec/x86_64_unknown_linux_musl.rs | 1 +
src/test/run-make/static-pie/Makefile | 15 +++++++
src/test/run-make/static-pie/test-aslr.rs | 43 +++++++++++++++++++
3 files changed, 59 insertions(+)
create mode 100644 src/test/run-make/static-pie/Makefile
create mode 100644 src/test/run-make/static-pie/test-aslr.rs
diff --git a/src/librustc_target/spec/x86_64_unknown_linux_musl.rs b/src/librustc_target/spec/x86_64_unknown_linux_musl.rs
index 34c628e8f67bd..3a22290da6858 100644
--- a/src/librustc_target/spec/x86_64_unknown_linux_musl.rs
+++ b/src/librustc_target/spec/x86_64_unknown_linux_musl.rs
@@ -6,6 +6,7 @@ pub fn target() -> TargetResult {
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.stack_probes = true;
+ base.static_position_independent_executables = true;
Ok(Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
diff --git a/src/test/run-make/static-pie/Makefile b/src/test/run-make/static-pie/Makefile
new file mode 100644
index 0000000000000..1d3cc82138927
--- /dev/null
+++ b/src/test/run-make/static-pie/Makefile
@@ -0,0 +1,15 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-x86_64-unknown-linux-musl
+
+# How to manually run this
+# $ ./x.py test --target x86_64-unknown-linux-musl src/test/run-make/static-pie
+
+all:
+ $(RUSTC) --target $(TARGET) -C target-feature=+crt-static test-aslr.rs
+ # Check that no dynamic interpreter is set
+ ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP
+ # Check that we have a dynamic executable
+ readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC
+ # Check for address space layout randomization
+ $(call RUN,test-aslr) --test-aslr
diff --git a/src/test/run-make/static-pie/test-aslr.rs b/src/test/run-make/static-pie/test-aslr.rs
new file mode 100644
index 0000000000000..f28e00f7f4cf9
--- /dev/null
+++ b/src/test/run-make/static-pie/test-aslr.rs
@@ -0,0 +1,43 @@
+const NUM_RUNS: usize = 10;
+
+fn run_self(exe: &str) -> usize {
+ use std::process::Command;
+ let mut set = std::collections::HashSet::new();
+
+ let mut cmd = Command::new(exe);
+ cmd.arg("--report");
+ (0..NUM_RUNS).for_each(|_| {
+ set.insert(cmd.output().expect("failed to execute process").stdout);
+ });
+ set.len()
+}
+
+fn main() {
+ let mut args = std::env::args();
+ let arg0 = args.next().unwrap();
+ match args.next() {
+ Some(s) if s.eq("--report") => {
+ println!("main = {:#?}", &main as *const _);
+ }
+ Some(s) if s.eq("--test-no-aslr") => {
+ let cnt = run_self(&arg0);
+ if cnt != 1 {
+ eprintln!("FAIL: {} most likely ASLR", arg0);
+ std::process::exit(1);
+ }
+ println!("PASS: {} does no ASLR", arg0);
+ }
+ Some(s) if s.eq("--test-aslr") => {
+ let cnt = run_self(&arg0);
+ if cnt != NUM_RUNS {
+ eprintln!("FAIL: {} most likely no ASLR", arg0);
+ std::process::exit(1);
+ }
+ println!("PASS: {} does ASLR", arg0);
+ }
+ Some(_) | None => {
+ println!("Usage: {} --test-no-aslr | --test-aslr", arg0);
+ std::process::exit(1);
+ }
+ }
+}
From 9e510085ecaedaee86b44410a4b3e4c85d97d6e0 Mon Sep 17 00:00:00 2001
From: Alexis Bourget
Date: Mon, 15 Jun 2020 15:19:02 +0200
Subject: [PATCH 045/123] Complete the std::time documentation to warn about
the inconsistencies between OS
---
src/libstd/time.rs | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index c36e78b1d004e..c58168bd446d7 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -60,6 +60,21 @@ pub use core::time::Duration;
/// }
/// ```
///
+/// # OS-specific behaviors
+///
+/// An `Instant` is a wrapper around system-specific types and it may behave
+/// differently depending on the underlying operating system. For example,
+/// the following snippet is fine on Linux but panics on macOS:
+///
+/// ```no_run
+/// use std::time::{Instant, Duration};
+///
+/// let now = Instant::now();
+/// let max_nanoseconds = u64::MAX / 1_000_000_000;
+/// let duration = Duration::new(max_nanoseconds, 0);
+/// println!("{:?}", now + duration);
+/// ```
+///
/// # Underlying System calls
/// Currently, the following system calls are being used to get the current time using `now()`:
///
From d6156e8fe5619143c687983d3ffa5b7ccc37c77e Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Mon, 8 Jun 2020 09:02:57 -0700
Subject: [PATCH 046/123] Change how compiler-builtins gets many CGUs
This commit intends to fix an accidental regression from #70846. The
goal of #70846 was to build compiler-builtins with a maximal number of
CGUs to ensure that each module in the source corresponds to an object
file. This high degree of control for compiler-builtins is desirable to
ensure that there's at most one exported symbol per CGU, ideally
enabling compiler-builtins to not conflict with the system libgcc as
often.
In #70846, however, only part of the compiler understands that
compiler-builtins is built with many CGUs. The rest of the compiler
thinks it's building with `sess.codegen_units()`. Notably the
calculation of `sess.lto()` consults `sess.codegen_units()`, which when
there's only one CGU it disables ThinLTO. This means that
compiler-builtins is built without ThinLTO, which is quite harmful to
performance! This is the root of the cause from #73135 where intrinsics
were found to not be inlining trivial functions.
The fix applied in this commit is to remove the special-casing of
compiler-builtins in the compiler. Instead the build system is now
responsible for special-casing compiler-builtins. It doesn't know
exactly how many CGUs will be needed but it passes a large number that
is assumed to be much greater than the number of source-level modules
needed. After reading the various locations in the compiler source, this
seemed like the best solution rather than adding more and more special
casing in the compiler for compiler-builtins.
Closes #73135
---
Cargo.toml | 13 ++++++
src/librustc_mir/monomorphize/partitioning.rs | 9 +----
.../partitioning/compiler-builtins.rs | 40 -------------------
3 files changed, 14 insertions(+), 48 deletions(-)
delete mode 100644 src/test/codegen-units/partitioning/compiler-builtins.rs
diff --git a/Cargo.toml b/Cargo.toml
index f2177a99a9b88..f10d539d8296b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,6 +42,19 @@ debug-assertions = false
debug = false
debug-assertions = false
+[profile.release.package.compiler_builtins]
+# For compiler-builtins we always use a high number of codegen units.
+# The goal here is to place every single intrinsic into its own object
+# file to avoid symbol clashes with the system libgcc if possible. Note
+# that this number doesn't actually produce this many object files, we
+# just don't create more than this number of object files.
+#
+# It's a bit of a bummer that we have to pass this here, unfortunately.
+# Ideally this would be specified through an env var to Cargo so Cargo
+# knows how many CGUs are for this specific crate, but for now
+# per-crate configuration isn't specifiable in the environment.
+codegen-units = 10000
+
# We want the RLS to use the version of Cargo that we've got vendored in this
# repository to ensure that the same exact version of Cargo is used by both the
# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index db1ea72c0a531..a945c1d626a9a 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -454,18 +454,11 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
fn merge_codegen_units<'tcx>(
tcx: TyCtxt<'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- mut target_cgu_count: usize,
+ target_cgu_count: usize,
) {
assert!(target_cgu_count >= 1);
let codegen_units = &mut initial_partitioning.codegen_units;
- if tcx.is_compiler_builtins(LOCAL_CRATE) {
- // Compiler builtins require some degree of control over how mono items
- // are partitioned into compilation units. Provide it by keeping the
- // original partitioning when compiling the compiler builtins crate.
- target_cgu_count = codegen_units.len();
- }
-
// Note that at this point in time the `codegen_units` here may not be in a
// deterministic order (but we know they're deterministically the same set).
// We want this merging to produce a deterministic ordering of codegen units
diff --git a/src/test/codegen-units/partitioning/compiler-builtins.rs b/src/test/codegen-units/partitioning/compiler-builtins.rs
deleted file mode 100644
index 25195743b0400..0000000000000
--- a/src/test/codegen-units/partitioning/compiler-builtins.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Verifies that during compiler_builtins compilation the codegen units are kept
-// unmerged. Even when only a single codegen unit is requested with -Ccodegen-units=1.
-//
-// compile-flags: -Zprint-mono-items=eager -Ccodegen-units=1
-
-#![compiler_builtins]
-#![crate_type="lib"]
-#![feature(compiler_builtins)]
-
-mod atomics {
- //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_1[0] @@ compiler_builtins-cgu.0[External]
- #[no_mangle]
- pub extern "C" fn sync_1() {}
-
- //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_2[0] @@ compiler_builtins-cgu.0[External]
- #[no_mangle]
- pub extern "C" fn sync_2() {}
-
- //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_3[0] @@ compiler_builtins-cgu.0[External]
- #[no_mangle]
- pub extern "C" fn sync_3() {}
-}
-
-mod x {
- //~ MONO_ITEM fn compiler_builtins::x[0]::x[0] @@ compiler_builtins-cgu.1[External]
- #[no_mangle]
- pub extern "C" fn x() {}
-}
-
-mod y {
- //~ MONO_ITEM fn compiler_builtins::y[0]::y[0] @@ compiler_builtins-cgu.2[External]
- #[no_mangle]
- pub extern "C" fn y() {}
-}
-
-mod z {
- //~ MONO_ITEM fn compiler_builtins::z[0]::z[0] @@ compiler_builtins-cgu.3[External]
- #[no_mangle]
- pub extern "C" fn z() {}
-}
From e390acdfccdc5297e8fbb186bbb890cb6a3d0e57 Mon Sep 17 00:00:00 2001
From: Gary Guo
Date: Mon, 15 Jun 2020 15:59:51 +0100
Subject: [PATCH 047/123] Use expr_ty_adjusted in convert_place_op_to_mutable
---
src/librustc_typeck/check/reconciliation.rs | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/src/librustc_typeck/check/reconciliation.rs b/src/librustc_typeck/check/reconciliation.rs
index b05155ae2aedd..0a4293140a82a 100644
--- a/src/librustc_typeck/check/reconciliation.rs
+++ b/src/librustc_typeck/check/reconciliation.rs
@@ -89,17 +89,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
+ // Need to deref because overloaded place ops take self by-reference.
let base_ty = self
.tables
.borrow()
- .expr_adjustments(base_expr)
- .last()
- .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target);
- let base_ty = self.resolve_vars_if_possible(&base_ty);
-
- // Need to deref because overloaded place ops take self by-reference.
- let base_ty =
- base_ty.builtin_deref(false).expect("place op takes something that is not a ref").ty;
+ .expr_ty_adjusted(base_expr)
+ .builtin_deref(false)
+ .expect("place op takes something that is not a ref")
+ .ty;
let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op);
let method = match method {
From e857696cf8c3b4a4381d00424f165c10f93a9ebd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?=
Date: Sun, 14 Jun 2020 21:36:25 -0700
Subject: [PATCH 048/123] Tweak "non-primitive cast" error
- Suggest borrowing expression if it would allow cast to work.
- Suggest using `::from()` when appropriate.
- Minor tweak to `;` typo suggestion.
Partily address #47136.
---
src/libcore/convert/mod.rs | 1 +
src/librustc_parse/parser/diagnostics.rs | 2 +-
src/librustc_span/symbol.rs | 1 +
src/librustc_typeck/check/cast.rs | 107 ++++++++++++++----
src/test/ui/cast/cast-from-nil.stderr | 4 +-
src/test/ui/cast/cast-to-bare-fn.stderr | 8 +-
src/test/ui/cast/cast-to-nil.stderr | 4 +-
...-to-unsized-trait-object-suggestion.stderr | 2 +-
src/test/ui/closures/closure-no-fn-3.stderr | 4 +-
.../ui/coercion/coerce-to-bang-cast.stderr | 8 +-
.../const-eval/const-eval-overflow-4b.stderr | 2 +-
src/test/ui/error-codes/E0604.stderr | 2 +-
src/test/ui/error-codes/E0605.stderr | 8 +-
src/test/ui/error-festival.stderr | 6 +-
src/test/ui/fat-ptr-cast.stderr | 4 +-
src/test/ui/issues/issue-10991.stderr | 4 +-
src/test/ui/issues/issue-16048.rs | 4 +-
src/test/ui/issues/issue-16048.stderr | 8 +-
src/test/ui/issues/issue-17441.stderr | 2 +-
src/test/ui/issues/issue-22289.stderr | 7 +-
src/test/ui/issues/issue-22312.rs | 2 +-
src/test/ui/issues/issue-22312.stderr | 7 +-
src/test/ui/issues/issue-2995.stderr | 4 +-
src/test/ui/issues/issue-45730.stderr | 18 +--
.../ui/mismatched_types/cast-rfc0401.stderr | 22 +---
.../ui/mismatched_types/issue-26480.stderr | 3 +-
src/test/ui/nonscalar-cast.fixed | 16 +++
src/test/ui/nonscalar-cast.rs | 8 ++
src/test/ui/nonscalar-cast.stderr | 6 +-
.../ui/order-dependent-cast-inference.stderr | 6 +-
.../ui/tag-variant-cast-non-nullary.fixed | 20 ++++
src/test/ui/tag-variant-cast-non-nullary.rs | 11 ++
.../ui/tag-variant-cast-non-nullary.stderr | 6 +-
.../never_reveal_concrete_type.stderr | 4 +-
.../uninhabited/uninhabited-enum-cast.stderr | 4 +-
35 files changed, 204 insertions(+), 121 deletions(-)
create mode 100644 src/test/ui/nonscalar-cast.fixed
create mode 100644 src/test/ui/tag-variant-cast-non-nullary.fixed
diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs
index eef9ee7cb0093..8ff1ced53b071 100644
--- a/src/libcore/convert/mod.rs
+++ b/src/libcore/convert/mod.rs
@@ -374,6 +374,7 @@ pub trait Into: Sized {
/// [`Into`]: trait.Into.html
/// [`from`]: trait.From.html#tymethod.from
/// [book]: ../../book/ch09-00-error-handling.html
+#[rustc_diagnostic_item = "from_trait"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(on(
all(_Self = "&str", T = "std::string::String"),
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 660a63841bcef..dafc0a9e048a4 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -961,7 +961,7 @@ impl<'a> Parser<'a> {
self.bump();
let sp = self.prev_token.span;
self.struct_span_err(sp, &msg)
- .span_suggestion(sp, "change this to `;`", ";".to_string(), appl)
+ .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
.emit();
return Ok(());
} else if self.look_ahead(0, |t| {
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index d165409696eca..9925e631c5c20 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -343,6 +343,7 @@ symbols! {
from_method,
from_ok,
from_usize,
+ from_trait,
fundamental,
future,
Future,
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 46d6706cbf429..bad009f4039af 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -43,6 +43,7 @@ use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
use rustc_session::lint;
use rustc_session::Session;
+use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
@@ -333,10 +334,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
"only `u8` can be cast as `char`, not `{}`",
self.expr_ty
)
+ .span_label(self.span, "invalid cast")
.emit();
}
CastError::NonScalar => {
- type_error_struct!(
+ let mut err = type_error_struct!(
fcx.tcx.sess,
self.span,
self.expr_ty,
@@ -344,12 +346,75 @@ impl<'a, 'tcx> CastCheck<'tcx> {
"non-primitive cast: `{}` as `{}`",
self.expr_ty,
fcx.ty_to_string(self.cast_ty)
- )
- .note(
- "an `as` expression can only be used to convert between \
- primitive types. Consider using the `From` trait",
- )
- .emit();
+ );
+ let mut sugg = None;
+ if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind {
+ if fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
+ {
+ sugg = Some(format!("&{}", mutbl.prefix_str()));
+ }
+ }
+ if let Some(sugg) = sugg {
+ err.span_label(self.span, "invalid cast");
+ err.span_suggestion_verbose(
+ self.expr.span.shrink_to_lo(),
+ "borrow the value for the cast to be valid",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ } else if !matches!(
+ self.cast_ty.kind,
+ ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
+ ) {
+ let mut label = true;
+ // Check `impl From for self.cast_ty {}` for accurate suggestion:
+ if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+ if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
+ let ty = fcx.resolve_vars_if_possible(&self.cast_ty);
+ // Erase regions to avoid panic in `prove_value` when calling
+ // `type_implements_trait`.
+ let ty = fcx.tcx.erase_regions(&ty);
+ let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty);
+ let expr_ty = fcx.tcx.erase_regions(&expr_ty);
+ let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
+ // Check for infer types because cases like `Option<{integer}>` would
+ // panic otherwise.
+ if !expr_ty.has_infer_types()
+ && fcx.tcx.type_implements_trait((
+ from_trait,
+ ty,
+ ty_params,
+ fcx.param_env,
+ ))
+ {
+ label = false;
+ err.span_suggestion(
+ self.span,
+ "consider using the `From` trait instead",
+ format!("{}::from({})", self.cast_ty, snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ let msg = "an `as` expression can only be used to convert between primitive \
+ types or to coerce to a specific trait object";
+ if label {
+ err.span_label(self.span, msg);
+ } else {
+ err.note(msg);
+ }
+ } else {
+ err.span_label(self.span, "invalid cast");
+ }
+ err.emit();
}
CastError::SizedUnsizedCast => {
use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
@@ -370,21 +435,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
};
let mut err = struct_span_err!(
fcx.tcx.sess,
- self.span,
+ if unknown_cast_to { self.cast_span } else { self.span },
E0641,
"cannot cast {} a pointer of an unknown kind",
if unknown_cast_to { "to" } else { "from" }
);
- err.note(
- "the type information given here is insufficient to check whether \
- the pointer cast is valid",
- );
if unknown_cast_to {
- err.span_suggestion_short(
- self.cast_span,
- "consider giving more type information",
- String::new(),
- Applicability::Unspecified,
+ err.span_label(self.cast_span, "needs more type information");
+ err.note(
+ "the type information given here is insufficient to check whether \
+ the pointer cast is valid",
+ );
+ } else {
+ err.span_label(
+ self.span,
+ "the type information given here is insufficient to check whether \
+ the pointer cast is valid",
);
}
err.emit();
@@ -438,13 +504,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
Ok(s) => {
err.span_suggestion(
self.cast_span,
- "try casting to a `Box` instead",
+ "you can cast to a `Box` instead",
format!("Box<{}>", s),
Applicability::MachineApplicable,
);
}
Err(_) => {
- err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr));
+ err.span_help(
+ self.cast_span,
+ &format!("you might have meant `Box<{}>`", tstr),
+ );
}
}
}
diff --git a/src/test/ui/cast/cast-from-nil.stderr b/src/test/ui/cast/cast-from-nil.stderr
index c8e3628a7ded8..dab133cfb4b67 100644
--- a/src/test/ui/cast/cast-from-nil.stderr
+++ b/src/test/ui/cast/cast-from-nil.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `u32`
--> $DIR/cast-from-nil.rs:2:21
|
LL | fn main() { let u = (assert!(true) as u32); }
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
diff --git a/src/test/ui/cast/cast-to-bare-fn.stderr b/src/test/ui/cast/cast-to-bare-fn.stderr
index 84933dca929a4..d97b0c5f8aadc 100644
--- a/src/test/ui/cast/cast-to-bare-fn.stderr
+++ b/src/test/ui/cast/cast-to-bare-fn.stderr
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `fn(isize) {foo}` as `extern "C" fn() -> isize
--> $DIR/cast-to-bare-fn.rs:5:13
|
LL | let x = foo as extern "C" fn() -> isize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error[E0605]: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)`
--> $DIR/cast-to-bare-fn.rs:7:13
|
LL | let y = v as extern "Rust" fn(isize) -> (isize, isize);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error: aborting due to 2 previous errors
diff --git a/src/test/ui/cast/cast-to-nil.stderr b/src/test/ui/cast/cast-to-nil.stderr
index 478f6b69dafc8..29a9baffd71d7 100644
--- a/src/test/ui/cast/cast-to-nil.stderr
+++ b/src/test/ui/cast/cast-to-nil.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `u32` as `()`
--> $DIR/cast-to-nil.rs:2:21
|
LL | fn main() { let u = 0u32 as (); }
- | ^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
index ffa02533d8b66..9b86f8d4def86 100644
--- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
+++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
@@ -12,7 +12,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::ma
LL | Box::new(1) as dyn Send;
| ^^^^^^^^^^^^^^^--------
| |
- | help: try casting to a `Box` instead: `Box`
+ | help: you can cast to a `Box` instead: `Box`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr
index ab6056b65473e..4b3b4be798fc1 100644
--- a/src/test/ui/closures/closure-no-fn-3.stderr
+++ b/src/test/ui/closures/closure-no-fn-3.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b
--> $DIR/closure-no-fn-3.rs:6:27
|
LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error: aborting due to previous error
diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr
index ff30ebc09c63a..d3adbd5158dbb 100644
--- a/src/test/ui/coercion/coerce-to-bang-cast.stderr
+++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `i32` as `!`
--> $DIR/coerce-to-bang-cast.rs:6:13
|
LL | let y = {return; 22} as !;
- | ^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `i32` as `!`
--> $DIR/coerce-to-bang-cast.rs:11:13
|
LL | let y = 22 as !;
- | ^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
index 5b2c4116c4b1d..e4d256c0ad192 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
@@ -16,7 +16,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
--> $DIR/const-eval-overflow-4b.rs:25:13
|
LL | : [u32; 5i8 as char as usize]
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ invalid cast
error: aborting due to 3 previous errors
diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr
index 5861bdcb7a953..18835310bd5e8 100644
--- a/src/test/ui/error-codes/E0604.stderr
+++ b/src/test/ui/error-codes/E0604.stderr
@@ -2,7 +2,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/E0604.rs:2:5
|
LL | 1u32 as char;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ invalid cast
error: aborting due to previous error
diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr
index 95e899db8b7e9..f23d2008e0b5f 100644
--- a/src/test/ui/error-codes/E0605.stderr
+++ b/src/test/ui/error-codes/E0605.stderr
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `u8` as `std::vec::Vec`
--> $DIR/E0605.rs:3:5
|
LL | x as Vec;
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `*const u8` as `&u8`
--> $DIR/E0605.rs:6:5
|
LL | v as &u8;
- | ^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 7f524230ef006..905195d4ad963 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -42,15 +42,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/error-festival.rs:25:5
|
LL | 0u32 as char;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ invalid cast
error[E0605]: non-primitive cast: `u8` as `std::vec::Vec`
--> $DIR/error-festival.rs:29:5
|
LL | x as Vec;
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0054]: cannot cast as `bool`
--> $DIR/error-festival.rs:33:24
diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr
index 93e1471838f72..56d5a26beb04e 100644
--- a/src/test/ui/fat-ptr-cast.stderr
+++ b/src/test/ui/fat-ptr-cast.stderr
@@ -34,9 +34,7 @@ error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize`
--> $DIR/fat-ptr-cast.rs:14:5
|
LL | b as usize;
- | ^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0606]: casting `*const [i32]` as `usize` is invalid
--> $DIR/fat-ptr-cast.rs:15:5
diff --git a/src/test/ui/issues/issue-10991.stderr b/src/test/ui/issues/issue-10991.stderr
index f12539b47cf44..5b8a182338693 100644
--- a/src/test/ui/issues/issue-10991.stderr
+++ b/src/test/ui/issues/issue-10991.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `usize`
--> $DIR/issue-10991.rs:3:14
|
LL | let _t = nil as usize;
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-16048.rs b/src/test/ui/issues/issue-16048.rs
index 7d24f3a40a742..eaf6acff26bf3 100644
--- a/src/test/ui/issues/issue-16048.rs
+++ b/src/test/ui/issues/issue-16048.rs
@@ -18,12 +18,12 @@ impl<'a> Test<'a> for Foo<'a> {
}
impl<'a> NoLifetime for Foo<'a> {
- fn get<'p, T : Test<'a>>(&self) -> T {
+ fn get<'p, T: Test<'a> + From>>(&self) -> T {
//~^ ERROR E0195
//~| NOTE lifetimes do not match method in trait
return *self as T;
//~^ ERROR non-primitive cast: `Foo<'a>` as `T`
- //~| NOTE an `as` expression can only be used to convert between primitive types.
+ //~| NOTE an `as` expression can only be used to convert between primitive types
}
}
diff --git a/src/test/ui/issues/issue-16048.stderr b/src/test/ui/issues/issue-16048.stderr
index a137bcdf1915e..73610942d7a7e 100644
--- a/src/test/ui/issues/issue-16048.stderr
+++ b/src/test/ui/issues/issue-16048.stderr
@@ -4,16 +4,16 @@ error[E0195]: lifetime parameters or bounds on method `get` do not match the tra
LL | fn get<'p, T : Test<'p>>(&self) -> T;
| ------------------ lifetimes in impl do not match this method in trait
...
-LL | fn get<'p, T : Test<'a>>(&self) -> T {
- | ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+LL | fn get<'p, T: Test<'a> + From>>(&self) -> T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
error[E0605]: non-primitive cast: `Foo<'a>` as `T`
--> $DIR/issue-16048.rs:24:16
|
LL | return *self as T;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)`
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr
index 0ab035515a051..b63a3995d255d 100644
--- a/src/test/ui/issues/issue-17441.stderr
+++ b/src/test/ui/issues/issue-17441.stderr
@@ -16,7 +16,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box` as `dyn std::fmt::D
LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug;
| ^^^^^^^^^^^^^^^^^^^^^-------------------
| |
- | help: try casting to a `Box` instead: `Box`
+ | help: you can cast to a `Box` instead: `Box`
error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug`
--> $DIR/issue-17441.rs:8:16
diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr
index cc7ace30cabef..4c35deb1fbe4e 100644
--- a/src/test/ui/issues/issue-22289.stderr
+++ b/src/test/ui/issues/issue-22289.stderr
@@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)`
--> $DIR/issue-22289.rs:2:5
|
LL | 0 as &dyn std::any::Any;
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+ |
+LL | &0 as &dyn std::any::Any;
+ | ^
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-22312.rs b/src/test/ui/issues/issue-22312.rs
index 250fec2588702..4e359b3412a71 100644
--- a/src/test/ui/issues/issue-22312.rs
+++ b/src/test/ui/issues/issue-22312.rs
@@ -1,6 +1,6 @@
use std::ops::Index;
-pub trait Array2D: Index {
+pub trait Array2D: Index + Sized {
fn rows(&self) -> usize;
fn columns(&self) -> usize;
fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a >::Output> {
diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr
index fc32fd376b75a..28564b074633b 100644
--- a/src/test/ui/issues/issue-22312.stderr
+++ b/src/test/ui/issues/issue-22312.stderr
@@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index $DIR/issue-22312.rs:11:24
|
LL | let indexer = &(*self as &dyn Index>::Output>);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+ |
+LL | let indexer = &(&*self as &dyn Index>::Output>);
+ | ^
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr
index c316780d5f6a5..9f5968399a37d 100644
--- a/src/test/ui/issues/issue-2995.stderr
+++ b/src/test/ui/issues/issue-2995.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize`
--> $DIR/issue-2995.rs:2:22
|
LL | let _q: &isize = p as &isize;
- | ^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr
index d4ddba52df14a..d00f3d91b49da 100644
--- a/src/test/ui/issues/issue-45730.stderr
+++ b/src/test/ui/issues/issue-45730.stderr
@@ -1,30 +1,24 @@
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/issue-45730.rs:3:23
+ --> $DIR/issue-45730.rs:3:28
|
LL | let x: *const _ = 0 as _;
- | ^^^^^-
- | |
- | help: consider giving more type information
+ | ^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/issue-45730.rs:5:23
+ --> $DIR/issue-45730.rs:5:28
|
LL | let x: *const _ = 0 as *const _;
- | ^^^^^--------
- | |
- | help: consider giving more type information
+ | ^^^^^^^^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/issue-45730.rs:8:13
+ --> $DIR/issue-45730.rs:8:44
|
LL | let x = 0 as *const i32 as *const _ as *mut _;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
- | |
- | help: consider giving more type information
+ | ^^^^^^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index f94dfd100a6f4..95936de218b8f 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -24,41 +24,31 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
--> $DIR/cast-rfc0401.rs:29:13
|
LL | let _ = v as &u8;
- | ^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `*const u8` as `E`
--> $DIR/cast-rfc0401.rs:30:13
|
LL | let _ = v as E;
- | ^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `*const u8` as `fn()`
--> $DIR/cast-rfc0401.rs:31:13
|
LL | let _ = v as fn();
- | ^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^ invalid cast
error[E0605]: non-primitive cast: `*const u8` as `(u32,)`
--> $DIR/cast-rfc0401.rs:32:13
|
LL | let _ = v as (u32,);
- | ^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8`
--> $DIR/cast-rfc0401.rs:33:13
|
LL | let _ = Some(&v) as *const u8;
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0606]: casting `*const u8` as `f32` is invalid
--> $DIR/cast-rfc0401.rs:35:13
@@ -102,7 +92,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/cast-rfc0401.rs:41:13
|
LL | let _ = 0x61u32 as char;
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ invalid cast
error[E0606]: casting `bool` as `f32` is invalid
--> $DIR/cast-rfc0401.rs:43:13
diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr
index 69a9d03e474ba..d39b0a3207763 100644
--- a/src/test/ui/mismatched_types/issue-26480.stderr
+++ b/src/test/ui/mismatched_types/issue-26480.stderr
@@ -17,12 +17,11 @@ error[E0605]: non-primitive cast: `{integer}` as `()`
--> $DIR/issue-26480.rs:22:19
|
LL | ($x:expr) => ($x as ())
- | ^^^^^^^^
+ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
...
LL | cast!(2);
| --------- in this macro invocation
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
diff --git a/src/test/ui/nonscalar-cast.fixed b/src/test/ui/nonscalar-cast.fixed
new file mode 100644
index 0000000000000..0a4b98469b2b6
--- /dev/null
+++ b/src/test/ui/nonscalar-cast.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+ x: isize
+}
+
+impl From for isize {
+ fn from(val: Foo) -> isize {
+ val.x
+ }
+}
+
+fn main() {
+ println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605]
+}
diff --git a/src/test/ui/nonscalar-cast.rs b/src/test/ui/nonscalar-cast.rs
index 7e6f1fd038fb7..59fcf09666b24 100644
--- a/src/test/ui/nonscalar-cast.rs
+++ b/src/test/ui/nonscalar-cast.rs
@@ -1,8 +1,16 @@
+// run-rustfix
+
#[derive(Debug)]
struct Foo {
x: isize
}
+impl From for isize {
+ fn from(val: Foo) -> isize {
+ val.x
+ }
+}
+
fn main() {
println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605]
}
diff --git a/src/test/ui/nonscalar-cast.stderr b/src/test/ui/nonscalar-cast.stderr
index 9338688b037ff..2a7037121876d 100644
--- a/src/test/ui/nonscalar-cast.stderr
+++ b/src/test/ui/nonscalar-cast.stderr
@@ -1,10 +1,10 @@
error[E0605]: non-primitive cast: `Foo` as `isize`
- --> $DIR/nonscalar-cast.rs:7:20
+ --> $DIR/nonscalar-cast.rs:15:20
|
LL | println!("{}", Foo { x: 1 } as isize);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })`
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr
index ad50b415869dd..9f4ac0fea36ef 100644
--- a/src/test/ui/order-dependent-cast-inference.stderr
+++ b/src/test/ui/order-dependent-cast-inference.stderr
@@ -1,10 +1,8 @@
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/order-dependent-cast-inference.rs:5:17
+ --> $DIR/order-dependent-cast-inference.rs:5:22
|
LL | let mut y = 0 as *const _;
- | ^^^^^--------
- | |
- | help: consider giving more type information
+ | ^^^^^^^^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
diff --git a/src/test/ui/tag-variant-cast-non-nullary.fixed b/src/test/ui/tag-variant-cast-non-nullary.fixed
new file mode 100644
index 0000000000000..53e68c2ac6af6
--- /dev/null
+++ b/src/test/ui/tag-variant-cast-non-nullary.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+enum NonNullary {
+ Nullary,
+ Other(isize),
+}
+
+impl From for isize {
+ fn from(val: NonNullary) -> isize {
+ match val {
+ NonNullary::Nullary => 0,
+ NonNullary::Other(i) => i,
+ }
+ }
+}
+
+fn main() {
+ let v = NonNullary::Nullary;
+ let val = isize::from(v); //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
+}
diff --git a/src/test/ui/tag-variant-cast-non-nullary.rs b/src/test/ui/tag-variant-cast-non-nullary.rs
index bb34e82cdca37..0d0c6188ad114 100644
--- a/src/test/ui/tag-variant-cast-non-nullary.rs
+++ b/src/test/ui/tag-variant-cast-non-nullary.rs
@@ -1,8 +1,19 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
enum NonNullary {
Nullary,
Other(isize),
}
+impl From for isize {
+ fn from(val: NonNullary) -> isize {
+ match val {
+ NonNullary::Nullary => 0,
+ NonNullary::Other(i) => i,
+ }
+ }
+}
+
fn main() {
let v = NonNullary::Nullary;
let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
diff --git a/src/test/ui/tag-variant-cast-non-nullary.stderr b/src/test/ui/tag-variant-cast-non-nullary.stderr
index 87ec20f20d789..ae2f5a7aead55 100644
--- a/src/test/ui/tag-variant-cast-non-nullary.stderr
+++ b/src/test/ui/tag-variant-cast-non-nullary.stderr
@@ -1,10 +1,10 @@
error[E0605]: non-primitive cast: `NonNullary` as `isize`
- --> $DIR/tag-variant-cast-non-nullary.rs:8:15
+ --> $DIR/tag-variant-cast-non-nullary.rs:19:15
|
LL | let val = v as isize;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
index 70c99c944d654..360633bba622b 100644
--- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
+++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
@@ -16,9 +16,7 @@ error[E0605]: non-primitive cast: `NoReveal` as `&'static str`
--> $DIR/never_reveal_concrete_type.rs:14:13
|
LL | let _ = x as &'static str;
- | ^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
index a39af7832f8c9..a9f10dfec994a 100644
--- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
+++ b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `E` as `isize`
--> $DIR/uninhabited-enum-cast.rs:4:20
|
LL | println!("{}", (e as isize).to_string());
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
From 81c909488eebcba16610402349563380772e0d1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?=
Date: Fri, 29 May 2020 15:09:43 -0700
Subject: [PATCH 049/123] Suggest substituting `'static` lifetime in impl/dyn
`Trait + 'static` return types
---
.../nice_region_error/static_impl_trait.rs | 64 ++++++++--
src/librustc_middle/ty/context.rs | 13 +-
src/librustc_middle/ty/diagnostics.rs | 8 +-
...t_outlive_least_region_or_bound.nll.stderr | 38 +++++-
.../must_outlive_least_region_or_bound.rs | 21 ++++
.../must_outlive_least_region_or_bound.stderr | 117 ++++++++++++++++--
6 files changed, 232 insertions(+), 29 deletions(-)
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
index f4c86ddae604e..88d6c23d51441 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -4,6 +4,7 @@ use crate::infer::error_reporting::msg_span_from_free_region;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use rustc_errors::{Applicability, ErrorReported};
+use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
use rustc_middle::ty::RegionKind;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -20,8 +21,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
) = error.clone()
{
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
- let (fn_return_span, is_dyn) =
- self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
+ let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
+ let is_dyn = matches!(fn_return.kind, TyKind::TraitObject(..));
+ let fn_return_span = fn_return.span;
if sub_r == &RegionKind::ReStatic {
let sp = var_origin.span();
let return_sp = sub_origin.span();
@@ -67,12 +69,58 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
lifetime,
);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
- err.span_suggestion_verbose(
- fn_return_span.shrink_to_hi(),
- &msg,
- format!(" + {}", lifetime_name),
- Applicability::MaybeIncorrect,
- );
+ match fn_return.kind {
+ TyKind::Def(item_id, _) => {
+ let item = self.tcx().hir().item(item_id.id);
+ let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+ opaque
+ } else {
+ err.emit();
+ return Some(ErrorReported);
+ };
+ let (span, sugg) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ name: LifetimeName::Static,
+ span,
+ ..
+ }) => Some((*span, lifetime_name.clone())),
+ _ => None,
+ })
+ .next()
+ .unwrap_or_else(|| {
+ (
+ fn_return_span.shrink_to_hi(),
+ format!(" + {}", lifetime_name),
+ )
+ });
+
+ err.span_suggestion_verbose(
+ span,
+ &msg,
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ TyKind::TraitObject(_, lt) => {
+ let (span, sugg) = match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => (
+ fn_return_span.shrink_to_hi(),
+ format!(" + {}", lifetime_name),
+ ),
+ _ => (lt.span, lifetime_name),
+ };
+ err.span_suggestion_verbose(
+ span,
+ &msg,
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ }
}
err.emit();
return Some(ErrorReported);
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index d5be3508d2d80..4770993d9cb07 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -1383,7 +1383,10 @@ impl<'tcx> TyCtxt<'tcx> {
})
}
- pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> {
+ pub fn return_type_impl_or_dyn_trait(
+ &self,
+ scope_def_id: DefId,
+ ) -> Option<&'tcx hir::Ty<'tcx>> {
let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
let hir_output = match self.hir().get(hir_id) {
Node::Item(hir::Item {
@@ -1429,15 +1432,17 @@ impl<'tcx> TyCtxt<'tcx> {
let output = self.erase_late_bound_regions(&sig.output());
if output.is_impl_trait() {
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
- Some((fn_decl.output.span(), false))
+ if let hir::FnRetTy::Return(ty) = fn_decl.output {
+ return Some(ty);
+ }
} else {
let mut v = TraitObjectVisitor(vec![]);
rustc_hir::intravisit::walk_ty(&mut v, hir_output);
if v.0.len() == 1 {
- return Some((v.0[0], true));
+ return Some(v.0[0]);
}
- None
}
+ None
}
_ => None,
}
diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs
index 2e9aa724ac5af..3ca506fe0d590 100644
--- a/src/librustc_middle/ty/diagnostics.rs
+++ b/src/librustc_middle/ty/diagnostics.rs
@@ -236,21 +236,21 @@ pub fn suggest_constraining_type_param(
}
}
-pub struct TraitObjectVisitor(pub Vec);
-impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor {
+pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
+impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
type Map = rustc_hir::intravisit::ErasedMap<'v>;
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap {
hir::intravisit::NestedVisitorMap::None
}
- fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if let hir::TyKind::TraitObject(
_,
hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
) = ty.kind
{
- self.0.push(ty.span);
+ self.0.push(ty);
}
}
}
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
index 1806d2607a3ac..ca9ca8a9debe2 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -26,7 +26,34 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+ |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+ | - ^ returning this value requires that `'1` must outlive `'static`
+ | |
+ | let's call the lifetime of this reference `'1`
+ |
+ = help: consider replacing `'1` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+ | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+ = help: consider replacing `'a` with `'static`
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/must_outlive_least_region_or_bound.rs:15:41
+ |
+LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+ | ---- ^ lifetime `'a` required
+ | |
+ | help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+
+error: lifetime may not live long enough
+ --> $DIR/must_outlive_least_region_or_bound.rs:33:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
@@ -35,7 +62,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
= help: consider replacing `'a` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:38:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@@ -45,13 +72,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
= help: consider adding the following bound: `'b: 'a`
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:43:51
|
LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
-error: aborting due to 5 previous errors
+error: aborting due to 8 previous errors
-For more information about this error, try `rustc --explain E0310`.
+Some errors have detailed explanations: E0310, E0621.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
index 00f3490991b52..beafe9258209d 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
@@ -6,6 +6,27 @@ fn elided(x: &i32) -> impl Copy { x }
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
+fn elided2(x: &i32) -> impl Copy + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+//~^ ERROR explicit lifetime required in the type of `x`
+
+fn elided3(x: &i32) -> Box { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn elided4(x: &i32) -> Box { Box::new(x) }
+//~^ ERROR explicit lifetime required in the type of `x`
+
+fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index d7dae6a08a7b9..525e271bea9c3 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -27,7 +27,43 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^
error: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+ |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+ | ---- ------------------- ^ ...and is captured here
+ | | |
+ | | ...is required to be `'static` by this...
+ | data with this lifetime...
+ |
+help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 9:1
+ |
+LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
+ | ^^
+
+error: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+ | ------- ------------------- ^ ...and is captured here
+ | | |
+ | | ...is required to be `'static` by this...
+ | data with this lifetime...
+ |
+help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:14
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
+ | ^^
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/must_outlive_least_region_or_bound.rs:15:24
+ |
+LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+ | ---- ^^^^^^^^^^^^^^ lifetime `'a` required
+ | |
+ | help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+
+error: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:33:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ------- -------------------------------- ^ ...and is captured here
@@ -35,13 +71,13 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15
+help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 33:15
|
-LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
- | ^^^^
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
+ | ^^
error[E0623]: lifetime mismatch
- --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:38:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| ------- ^^^^^^^^^^^^^^^^
@@ -50,14 +86,79 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
| this parameter and the return type are declared with different lifetimes...
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:43:51
|
LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static {
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `T: 'static +`
-error: aborting due to 5 previous errors
+error: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ |
+LL | fn elided3(x: &i32) -> Box { Box::new(x) }
+ | ---- ---------^-
+ | | | |
+ | | | ...and is captured here
+ | | ...is required to be `'static` by this...
+ | data with this lifetime...
+ |
+help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1
+ |
+LL | fn elided3(x: &i32) -> Box { Box::new(x) }
+ | ^^^^
+
+error: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:21:59
+ |
+LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ------- ---------^-
+ | | | |
+ | | | ...and is captured here
+ | | ...is required to be `'static` by this...
+ | data with this lifetime...
+ |
+help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14
+ |
+LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ^^^^
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/must_outlive_least_region_or_bound.rs:24:51
+ |
+LL | fn elided4(x: &i32) -> Box { Box::new(x) }
+ | ---- ^^^^^^^^^^^ lifetime `'static` required
+ | |
+ | help: add explicit lifetime `'static` to the type of `x`: `&'static i32`
+
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 27:14...
+ --> $DIR/must_outlive_least_region_or_bound.rs:27:14
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ^^
+note: ...so that the expression is assignable
+ --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ^
+ = note: expected `&i32`
+ found `&'a i32`
+ = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the expression is assignable
+ --> $DIR/must_outlive_least_region_or_bound.rs:27:60
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>`
+ found `std::boxed::Box`
+
+error: aborting due to 12 previous errors
-Some errors have detailed explanations: E0310, E0623.
+Some errors have detailed explanations: E0310, E0495, E0621, E0623.
For more information about an error, try `rustc --explain E0310`.
From 4e90f177cc530371a314f51f522a4c2e70885e03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?=
Date: Fri, 29 May 2020 18:05:20 -0700
Subject: [PATCH 050/123] When `'static` is explicit, suggest constraining
argument with it
---
.../infer/error_reporting/mod.rs | 3 +-
.../nice_region_error/static_impl_trait.rs | 115 +++++++++++-------
src/librustc_middle/ty/diagnostics.rs | 5 +-
.../must_outlive_least_region_or_bound.rs | 2 +-
.../must_outlive_least_region_or_bound.stderr | 75 +++++++-----
src/test/ui/issues/issue-16922.stderr | 2 +-
...ect-lifetime-default-from-box-error.stderr | 2 +-
...ion-object-lifetime-in-coercion.nll.stderr | 19 ++-
.../region-object-lifetime-in-coercion.rs | 5 +-
.../region-object-lifetime-in-coercion.stderr | 61 +++++++---
.../regions-close-object-into-object-2.stderr | 32 ++---
.../regions-close-object-into-object-4.stderr | 32 ++---
.../regions-proc-bound-capture.nll.stderr | 11 ++
.../ui/regions/regions-proc-bound-capture.rs | 4 +-
.../regions/regions-proc-bound-capture.stderr | 25 ++--
.../dyn-trait-underscore.stderr | 2 +-
16 files changed, 237 insertions(+), 158 deletions(-)
create mode 100644 src/test/ui/regions/regions-proc-bound-capture.nll.stderr
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 12f7a9c0ca502..9cfa11dd7c813 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -2035,8 +2035,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.tcx.sess,
var_origin.span(),
E0495,
- "cannot infer an appropriate lifetime{} \
- due to conflicting requirements",
+ "cannot infer an appropriate lifetime{} due to conflicting requirements",
var_description
)
}
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 88d6c23d51441..e24535bba5fdc 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -10,6 +10,7 @@ use rustc_middle::ty::RegionKind;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the return type is a static impl Trait.
pub(super) fn try_report_static_impl_trait(&self) -> Option {
+ debug!("try_report_static_impl_trait(error={:?})", self.error);
if let Some(ref error) = self.error {
if let RegionResolutionError::SubSupConflict(
_,
@@ -18,19 +19,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
- ) = error.clone()
+ ) = error
{
+ debug!(
+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+ var_origin, sub_origin, sub_r, sup_origin, sup_r
+ );
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
+ debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
- let is_dyn = matches!(fn_return.kind, TyKind::TraitObject(..));
- let fn_return_span = fn_return.span;
- if sub_r == &RegionKind::ReStatic {
+ debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
+ if **sub_r == RegionKind::ReStatic {
let sp = var_origin.span();
let return_sp = sub_origin.span();
+ let param_info = self.find_param_with_region(sup_r, sub_r)?;
let mut err =
self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime");
- let param_info = self.find_param_with_region(sup_r, sub_r)?;
err.span_label(param_info.param_ty_span, "data with this lifetime...");
+ debug!("try_report_static_impl_trait: param_info={:?}", param_info);
// We try to make the output have fewer overlapping spans if possible.
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
@@ -60,14 +66,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
// only apply this suggestion onto functions with
// explicit non-desugar'able return.
- if fn_return_span.desugaring_kind().is_none() {
- let msg = format!(
- "to permit non-static references in {} `{} Trait` value, you can add \
- an explicit bound for {}",
- if is_dyn { "a" } else { "an" },
- if is_dyn { "dyn" } else { "impl" },
- lifetime,
- );
+ if fn_return.span.desugaring_kind().is_none() {
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
match fn_return.kind {
TyKind::Def(item_id, _) => {
@@ -78,7 +77,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
err.emit();
return Some(ErrorReported);
};
- let (span, sugg) = opaque
+
+ if let Some(span) = opaque
.bounds
.iter()
.filter_map(|arg| match arg {
@@ -86,38 +86,71 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
name: LifetimeName::Static,
span,
..
- }) => Some((*span, lifetime_name.clone())),
+ }) => Some(*span),
_ => None,
})
.next()
- .unwrap_or_else(|| {
- (
- fn_return_span.shrink_to_hi(),
- format!(" + {}", lifetime_name),
- )
- });
-
- err.span_suggestion_verbose(
- span,
- &msg,
- sugg,
- Applicability::MaybeIncorrect,
- );
- }
- TyKind::TraitObject(_, lt) => {
- let (span, sugg) = match lt.name {
- LifetimeName::ImplicitObjectLifetimeDefault => (
- fn_return_span.shrink_to_hi(),
+ {
+ err.span_suggestion_verbose(
+ span,
+ "consider changing the `impl Trait`'s explicit \
+ `'static` bound",
+ lifetime_name,
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ "alternatively, set an explicit `'static` lifetime to \
+ this parameter",
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "to permit non-static references in an `impl Trait` \
+ value, you can add an explicit bound for {}",
+ lifetime,
+ ),
format!(" + {}", lifetime_name),
- ),
- _ => (lt.span, lifetime_name),
+ Applicability::MaybeIncorrect,
+ );
};
- err.span_suggestion_verbose(
- span,
- &msg,
- sugg,
- Applicability::MaybeIncorrect,
- );
+ }
+ TyKind::TraitObject(_, lt) => {
+ match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "to permit non-static references in a trait object \
+ value, you can add an explicit bound for {}",
+ lifetime,
+ ),
+ format!(" + {}", lifetime_name),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ err.span_suggestion_verbose(
+ lt.span,
+ "consider changing the trait object's explicit \
+ `'static` bound",
+ lifetime_name,
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ &format!(
+ "alternatively, set an explicit `'static` lifetime \
+ in this parameter",
+ ),
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
_ => {}
}
diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs
index 3ca506fe0d590..a2812e117ed39 100644
--- a/src/librustc_middle/ty/diagnostics.rs
+++ b/src/librustc_middle/ty/diagnostics.rs
@@ -247,7 +247,10 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if let hir::TyKind::TraitObject(
_,
- hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
+ hir::Lifetime {
+ name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+ ..
+ },
) = ty.kind
{
self.0.push(ty);
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
index beafe9258209d..837244b022721 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
@@ -22,7 +22,7 @@ fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
//~^ ERROR cannot infer an appropriate lifetime
fn elided4(x: &i32) -> Box { Box::new(x) }
-//~^ ERROR explicit lifetime required in the type of `x`
+//~^ ERROR cannot infer an appropriate lifetime
fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
//~^ ERROR cannot infer an appropriate lifetime
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index 525e271bea9c3..96d4a121c16af 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -35,10 +35,14 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 9:1
+help: consider changing the `impl Trait`'s explicit `'static` bound
|
LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
| ^^
+help: alternatively, set an explicit `'static` lifetime to this parameter
+ |
+LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
+ | ^^^^^^^^^^^^
error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:12:55
@@ -49,10 +53,14 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:14
+help: consider changing the `impl Trait`'s explicit `'static` bound
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^
+help: alternatively, set an explicit `'static` lifetime to this parameter
+ |
+LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
+ | ^^^^^^^^^^^^
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:15:24
@@ -71,10 +79,14 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 33:15
+help: consider changing the `impl Trait`'s explicit `'static` bound
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
| ^^
+help: alternatively, set an explicit `'static` lifetime to this parameter
+ |
+LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
+ | ^^^^^^^^^^^^
error[E0623]: lifetime mismatch
--> $DIR/must_outlive_least_region_or_bound.rs:38:61
@@ -103,7 +115,7 @@ LL | fn elided3(x: &i32) -> Box { Box::new(x) }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1
+help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1
|
LL | fn elided3(x: &i32) -> Box { Box::new(x) }
| ^^^^
@@ -118,47 +130,48 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14
+help: to permit non-static references in a trait object value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14
|
LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
| ^^^^
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:24:51
+error: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:24:60
|
LL | fn elided4(x: &i32) -> Box { Box::new(x) }
- | ---- ^^^^^^^^^^^ lifetime `'static` required
- | |
- | help: add explicit lifetime `'static` to the type of `x`: `&'static i32`
-
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+ | ---- ---------^-
+ | | | |
+ | | | ...and is captured here
+ | data with this lifetime... ...is required to be `'static` by this...
|
-LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
- | ^
+help: consider changing the trait object's explicit `'static` bound
|
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 27:14...
- --> $DIR/must_outlive_least_region_or_bound.rs:27:14
+LL | fn elided4(x: &i32) -> Box { Box::new(x) }
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
|
-LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
- | ^^
-note: ...so that the expression is assignable
+LL | fn elided4(x: &'static i32) -> Box { Box::new(x) }
+ | ^^^^^^^^^^^^
+
+error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:27:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
- | ^
- = note: expected `&i32`
- found `&'a i32`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/must_outlive_least_region_or_bound.rs:27:60
+ | ------- ---------^-
+ | | | |
+ | | | ...and is captured here
+ | data with this lifetime... ...is required to be `'static` by this...
|
-LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
- | ^^^^^^^^^^^
- = note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>`
- found `std::boxed::Box`
+help: consider changing the trait object's explicit `'static` bound
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) }
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
+ |
+LL | fn explicit4<'a>(x: &'static i32) -> Box { Box::new(x) }
+ | ^^^^^^^^^^^^
error: aborting due to 12 previous errors
-Some errors have detailed explanations: E0310, E0495, E0621, E0623.
+Some errors have detailed explanations: E0310, E0621, E0623.
For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr
index 02d33aae023ff..038df47e1bd98 100644
--- a/src/test/ui/issues/issue-16922.stderr
+++ b/src/test/ui/issues/issue-16922.stderr
@@ -9,7 +9,7 @@ LL | Box::new(value) as Box
| | ...and is captured here
| ...is required to be `'static` by this...
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
+help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
|
LL | fn foo(value: &T) -> Box {
| ^^^^
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
index 70a9bf22b8db3..555622c9d13c1 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
@@ -7,7 +7,7 @@ LL | fn load(ss: &mut SomeStruct) -> Box {
LL | ss.r
| ^^^^ ...is captured and required to be `'static` here
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1
+help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1
|
LL | fn load(ss: &mut SomeStruct) -> Box {
| ^^^^
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
index bf02ba8eb9199..7e8f78067e08a 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
@@ -1,21 +1,21 @@
-error[E0621]: explicit lifetime required in the type of `v`
+error: lifetime may not live long enough
--> $DIR/region-object-lifetime-in-coercion.rs:8:12
|
LL | fn a(v: &[u8]) -> Box {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | - let's call the lifetime of this reference `'1`
LL | let x: Box = Box::new(v);
- | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+ | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
-error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+error: lifetime may not live long enough
+ --> $DIR/region-object-lifetime-in-coercion.rs:13:5
|
LL | fn b(v: &[u8]) -> Box {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | - let's call the lifetime of this reference `'1`
LL | Box::new(v)
- | ^^^^^^^^^^^ lifetime `'static` required
+ | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:20:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:19:5
|
LL | fn c(v: &[u8]) -> Box {
| - let's call the lifetime of this reference `'1`
@@ -24,7 +24,7 @@ LL | Box::new(v)
| ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:24:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:5
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box {
| -- -- lifetime `'b` defined here
@@ -37,4 +37,3 @@ LL | Box::new(v)
error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs
index d56eaf77b6646..5d199149c39b8 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs
@@ -5,13 +5,12 @@ trait Foo {}
impl<'a> Foo for &'a [u8] {}
fn a(v: &[u8]) -> Box {
- let x: Box = Box::new(v);
- //~^ ERROR explicit lifetime required in the type of `v` [E0621]
+ let x: Box = Box::new(v); //~ ERROR cannot infer an appropriate lifetime
x
}
fn b(v: &[u8]) -> Box {
- Box::new(v) //~ ERROR explicit lifetime required in the type of `v` [E0621]
+ Box::new(v) //~ ERROR cannot infer an appropriate lifetime
}
fn c(v: &[u8]) -> Box {
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index 1462af44cb15a..673300cebc26c 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -1,21 +1,45 @@
-error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/region-object-lifetime-in-coercion.rs:8:37
+error: cannot infer an appropriate lifetime
+ --> $DIR/region-object-lifetime-in-coercion.rs:8:46
|
LL | fn a(v: &[u8]) -> Box {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | ----- data with this lifetime...
LL | let x: Box = Box::new(v);
- | ^^^^^^^^^^^ lifetime `'static` required
+ | ---------^-
+ | | |
+ | | ...and is captured here
+ | ...is required to be `'static` by this...
+ |
+help: consider changing the trait object's explicit `'static` bound
+ |
+LL | fn a(v: &[u8]) -> Box {
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
+ |
+LL | fn a(v: &'static [u8]) -> Box {
+ | ^^^^^^^^^^^^^
-error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+error: cannot infer an appropriate lifetime
+ --> $DIR/region-object-lifetime-in-coercion.rs:13:14
|
LL | fn b(v: &[u8]) -> Box {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | ----- data with this lifetime...
LL | Box::new(v)
- | ^^^^^^^^^^^ lifetime `'static` required
+ | ---------^-
+ | | |
+ | | ...and is captured here
+ | ...is required to be `'static` by this...
+ |
+help: consider changing the trait object's explicit `'static` bound
+ |
+LL | fn b(v: &[u8]) -> Box {
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
+ |
+LL | fn b(v: &'static [u8]) -> Box {
+ | ^^^^^^^^^^^^^
error: cannot infer an appropriate lifetime
- --> $DIR/region-object-lifetime-in-coercion.rs:20:14
+ --> $DIR/region-object-lifetime-in-coercion.rs:19:14
|
LL | fn c(v: &[u8]) -> Box {
| ----- data with this lifetime...
@@ -26,36 +50,36 @@ LL | Box::new(v)
| | ...and is captured here
| ...is required to be `'static` by this...
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 17:1
+help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 16:1
|
LL | fn c(v: &[u8]) -> Box {
| ^^^^
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/region-object-lifetime-in-coercion.rs:24:14
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:14
|
LL | Box::new(v)
| ^
|
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 23:6...
- --> $DIR/region-object-lifetime-in-coercion.rs:23:6
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:6...
+ --> $DIR/region-object-lifetime-in-coercion.rs:22:6
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box {
| ^^
note: ...so that the expression is assignable
- --> $DIR/region-object-lifetime-in-coercion.rs:24:14
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:14
|
LL | Box::new(v)
| ^
= note: expected `&[u8]`
found `&'a [u8]`
-note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 23:9...
- --> $DIR/region-object-lifetime-in-coercion.rs:23:9
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 22:9...
+ --> $DIR/region-object-lifetime-in-coercion.rs:22:9
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box {
| ^^
note: ...so that the expression is assignable
- --> $DIR/region-object-lifetime-in-coercion.rs:24:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:5
|
LL | Box::new(v)
| ^^^^^^^^^^^
@@ -64,5 +88,4 @@ LL | Box::new(v)
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0495, E0621.
-For more information about an error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 147f7f3541816..982ed07232a80 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -1,28 +1,22 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error: cannot infer an appropriate lifetime
--> $DIR/regions-close-object-into-object-2.rs:10:11
|
+LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box {
+ | ------------------ data with this lifetime...
LL | box B(&*v) as Box
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
- --> $DIR/regions-close-object-into-object-2.rs:9:6
+ | ------^^^---------------
+ | | |
+ | | ...and is captured here
+ | ...is required to be `'static` by this...
|
-LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box {
- | ^^
-note: ...so that the type `(dyn A + 'a)` is not borrowed for too long
- --> $DIR/regions-close-object-into-object-2.rs:10:11
+help: consider changing the trait object's explicit `'static` bound
|
-LL | box B(&*v) as Box
- | ^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/regions-close-object-into-object-2.rs:10:5
+LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box {
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
|
-LL | box B(&*v) as Box
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected `std::boxed::Box<(dyn X + 'static)>`
- found `std::boxed::Box`
+LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index 6e7d6152cd09a..1b82098ee13c2 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -1,28 +1,22 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error: cannot infer an appropriate lifetime
--> $DIR/regions-close-object-into-object-4.rs:10:11
|
+LL | fn i<'a, T, U>(v: Box+'a>) -> Box {
+ | ---------------- data with this lifetime...
LL | box B(&*v) as Box
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
- --> $DIR/regions-close-object-into-object-4.rs:9:6
+ | ------^^^---------------
+ | | |
+ | | ...and is captured here
+ | ...is required to be `'static` by this...
|
-LL | fn i<'a, T, U>(v: Box+'a>) -> Box {
- | ^^
-note: ...so that the type `(dyn A + 'a)` is not borrowed for too long
- --> $DIR/regions-close-object-into-object-4.rs:10:11
+help: consider changing the trait object's explicit `'static` bound
|
-LL | box B(&*v) as Box
- | ^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/regions-close-object-into-object-4.rs:10:5
+LL | fn i<'a, T, U>(v: Box+'a>) -> Box {
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
|
-LL | box B(&*v) as Box
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected `std::boxed::Box<(dyn X + 'static)>`
- found `std::boxed::Box`
+LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A + 'static)>) -> Box {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-proc-bound-capture.nll.stderr b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr
new file mode 100644
index 0000000000000..75890b8581537
--- /dev/null
+++ b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/regions-proc-bound-capture.rs:9:5
+ |
+LL | fn static_proc(x: &isize) -> Box (isize) + 'static> {
+ | - let's call the lifetime of this reference `'1`
+LL | // This is illegal, because the region bound on `proc` is 'static.
+LL | Box::new(move || { *x })
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs
index 0c903b7384992..8617c0e9da8f7 100644
--- a/src/test/ui/regions/regions-proc-bound-capture.rs
+++ b/src/test/ui/regions/regions-proc-bound-capture.rs
@@ -4,9 +4,9 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> {
Box::new(move|| { *x })
}
-fn static_proc(x: &isize) -> Box(isize) + 'static> {
+fn static_proc(x: &isize) -> Box (isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static.
- Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
+ Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime
}
fn main() { }
diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr
index c53af34456ef3..e7bbfaababe8a 100644
--- a/src/test/ui/regions/regions-proc-bound-capture.stderr
+++ b/src/test/ui/regions/regions-proc-bound-capture.stderr
@@ -1,12 +1,23 @@
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/regions-proc-bound-capture.rs:9:5
+error: cannot infer an appropriate lifetime
+ --> $DIR/regions-proc-bound-capture.rs:9:14
|
-LL | fn static_proc(x: &isize) -> Box(isize) + 'static> {
- | ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize`
+LL | fn static_proc(x: &isize) -> Box (isize) + 'static> {
+ | ------ data with this lifetime...
LL | // This is illegal, because the region bound on `proc` is 'static.
-LL | Box::new(move|| { *x })
- | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+LL | Box::new(move || { *x })
+ | ---------^^^^^^^^^^^^^^-
+ | | |
+ | | ...and is captured here
+ | ...is required to be `'static` by this...
+ |
+help: consider changing the trait object's explicit `'static` bound
+ |
+LL | fn static_proc(x: &isize) -> Box (isize) + '_> {
+ | ^^
+help: alternatively, set an explicit `'static` lifetime in this parameter
+ |
+LL | fn static_proc(x: &'static isize) -> Box (isize) + 'static> {
+ | ^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
index 3577dd59289e5..4dc4aac6ceac4 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
@@ -7,7 +7,7 @@ LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to
LL | Box::new(items.iter())
| ---------------^^^^--- ...is captured and required to be `'static` here
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1
+help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1
|
LL | fn a(items: &[T]) -> Box + '_> {
| ^^^^
From 921f35fe73e8749dee8531f7fbaf2cb4958fa799 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?=
Date: Fri, 29 May 2020 18:59:42 -0700
Subject: [PATCH 051/123] Reduce verbosity of suggestion message and mention
lifetime in label
---
.../nice_region_error/static_impl_trait.rs | 87 ++++++++++---------
.../ui/async-await/issues/issue-62097.stderr | 2 +-
.../must_outlive_least_region_or_bound.stderr | 38 ++++----
.../static-return-lifetime-infered.stderr | 8 +-
src/test/ui/issues/issue-16922.stderr | 4 +-
...ect-lifetime-default-from-box-error.stderr | 4 +-
.../region-object-lifetime-in-coercion.stderr | 12 +--
.../regions-close-object-into-object-2.stderr | 4 +-
.../regions-close-object-into-object-4.stderr | 4 +-
.../regions/regions-proc-bound-capture.stderr | 4 +-
...types_pin_lifetime_impl_trait-async.stderr | 2 +-
..._self_types_pin_lifetime_impl_trait.stderr | 4 +-
.../missing-lifetimes-in-signature.stderr | 4 +-
.../dyn-trait-underscore.stderr | 4 +-
14 files changed, 95 insertions(+), 86 deletions(-)
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
index e24535bba5fdc..e9f165d309f8f 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -1,6 +1,5 @@
//! Error Reporting for static impl Traits.
-use crate::infer::error_reporting::msg_span_from_free_region;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use rustc_errors::{Applicability, ErrorReported};
@@ -33,9 +32,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let sp = var_origin.span();
let return_sp = sub_origin.span();
let param_info = self.find_param_with_region(sup_r, sub_r)?;
+ let (lifetime_name, lifetime) = if sup_r.has_name() {
+ (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+ } else {
+ ("'_".to_owned(), "the anonymous lifetime `'_`".to_string())
+ };
let mut err =
self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime");
- err.span_label(param_info.param_ty_span, "data with this lifetime...");
+ err.span_label(
+ param_info.param_ty_span,
+ &format!("this data with {}...", lifetime),
+ );
debug!("try_report_static_impl_trait: param_info={:?}", param_info);
// We try to make the output have fewer overlapping spans if possible.
@@ -60,10 +67,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
);
}
- let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r);
-
- let lifetime_name =
- if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
// only apply this suggestion onto functions with
// explicit non-desugar'able return.
if fn_return.span.desugaring_kind().is_none() {
@@ -93,8 +96,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
{
err.span_suggestion_verbose(
span,
- "consider changing the `impl Trait`'s explicit \
- `'static` bound",
+ &format!(
+ "consider changing the `impl Trait`'s explicit \
+ `'static` bound to {}",
+ lifetime,
+ ),
lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -118,40 +124,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
);
};
}
- TyKind::TraitObject(_, lt) => {
- match lt.name {
- LifetimeName::ImplicitObjectLifetimeDefault => {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "to permit non-static references in a trait object \
- value, you can add an explicit bound for {}",
- lifetime,
- ),
- format!(" + {}", lifetime_name),
- Applicability::MaybeIncorrect,
- );
- }
- _ => {
- err.span_suggestion_verbose(
- lt.span,
+ TyKind::TraitObject(_, lt) => match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "to permit non-static references in a trait object \
+ value, you can add an explicit bound for {}",
+ lifetime,
+ ),
+ format!(" + {}", lifetime_name),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ err.span_suggestion_verbose(
+ lt.span,
+ &format!(
"consider changing the trait object's explicit \
- `'static` bound",
- lifetime_name,
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- &format!(
- "alternatively, set an explicit `'static` lifetime \
- in this parameter",
- ),
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- }
+ `'static` bound to {}",
+ lifetime,
+ ),
+ lifetime_name,
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ &format!(
+ "alternatively, set an explicit `'static` lifetime \
+ in this parameter",
+ ),
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
}
- }
+ },
_ => {}
}
}
diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr
index af8fc2cd2ab45..fff43ae9f47bc 100644
--- a/src/test/ui/async-await/issues/issue-62097.stderr
+++ b/src/test/ui/async-await/issues/issue-62097.stderr
@@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime
LL | pub async fn run_dummy_fn(&self) {
| ^^^^^
| |
- | data with this lifetime...
+ | this data with the anonymous lifetime `'_`...
| ...is captured here...
LL | foo(|| self.bar()).await;
| --- ...and required to be `'static` by this
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index 96d4a121c16af..00b6ec38323c3 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -5,9 +5,9 @@ LL | fn elided(x: &i32) -> impl Copy { x }
| ---- --------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with the anonymous lifetime `'_`...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
+help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime `'_`
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ^^^^
@@ -19,9 +19,9 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| ------- --------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with lifetime `'a`...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 6:13
+help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for lifetime `'a`
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^
@@ -33,9 +33,9 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ---- ------------------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with the anonymous lifetime `'_`...
|
-help: consider changing the `impl Trait`'s explicit `'static` bound
+help: consider changing the `impl Trait`'s explicit `'static` bound to the anonymous lifetime `'_`
|
LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
| ^^
@@ -51,9 +51,9 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ------- ------------------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with lifetime `'a`...
|
-help: consider changing the `impl Trait`'s explicit `'static` bound
+help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a`
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^
@@ -77,9 +77,9 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ------- -------------------------------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with lifetime `'a`...
|
-help: consider changing the `impl Trait`'s explicit `'static` bound
+help: consider changing the `impl Trait`'s explicit `'static` bound to lifetime `'a`
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
| ^^
@@ -113,9 +113,9 @@ LL | fn elided3(x: &i32) -> Box { Box::new(x) }
| | | |
| | | ...and is captured here
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with the anonymous lifetime `'_`...
|
-help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1
+help: to permit non-static references in a trait object value, you can add an explicit bound for the anonymous lifetime `'_`
|
LL | fn elided3(x: &i32) -> Box { Box::new(x) }
| ^^^^
@@ -128,9 +128,9 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) }
| | | |
| | | ...and is captured here
| | ...is required to be `'static` by this...
- | data with this lifetime...
+ | this data with lifetime `'a`...
|
-help: to permit non-static references in a trait object value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14
+help: to permit non-static references in a trait object value, you can add an explicit bound for lifetime `'a`
|
LL | fn explicit3<'a>(x: &'a i32) -> Box