Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #73299

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9cee22c
Display information about captured variable in `FnMut` error
Aaron1011 May 24, 2020
4548eb8
Clarify the behaviour of Pattern when used with methods like str::con…
poliorcetics Jun 2, 2020
e9b67d2
Fix link error with #[thread_local] introduced by #71192
Amanieu Jun 6, 2020
6f6620b
Rename "cyclone" to "apple-a7" per changes in upstream LLVM
trevyn Jun 7, 2020
687767a
Suggest substituting `'static` lifetime in impl/dyn `Trait + 'static`…
estebank May 29, 2020
c91320f
When `'static` is explicit, suggest constraining argument with it
estebank May 30, 2020
abf74b9
Reduce verbosity of suggestion message and mention lifetime in label
estebank May 30, 2020
50c422e
Move overlapping span to a note
estebank May 30, 2020
17951e2
Tweak output for overlapping required/captured spans
estebank May 30, 2020
19bb589
Tweak wording and add error code
estebank May 30, 2020
3cfecde
review comments: wording
estebank Jun 1, 2020
bdfb9b1
Use note for requirement source span
estebank Jun 2, 2020
215de3b
Register new eror code
estebank Jun 2, 2020
187e105
small tweaks
estebank Jun 2, 2020
6145918
Change E0758 to E0759 to avoid conflict with #72912
estebank Jun 3, 2020
2af53e9
Add -O compile flag to test
Amanieu Jun 10, 2020
975f7df
compiletest: Add directives to detect sanitizer support
tmiasko Jun 5, 2020
57b54c4
Use the built cargo for cargotest.
ehuss Jun 12, 2020
b126f32
Fix links when pinging notification groups
LeSeulArtichaut Jun 12, 2020
b6e45f0
Rollup merge of #72598 - Aaron1011:feature/fnmut-capture-span, r=niko…
Dylan-DPC Jun 13, 2020
7cec851
Rollup merge of #72804 - estebank:opaque-missing-lts-in-fn-2, r=nikom…
Dylan-DPC Jun 13, 2020
22c222f
Rollup merge of #72932 - poliorcetics:pattern-contains-behaviour, r=h…
Dylan-DPC Jun 13, 2020
9163d1b
Rollup merge of #73044 - tmiasko:compiletest-san, r=nikomatsakis
Dylan-DPC Jun 13, 2020
c69bfd0
Rollup merge of #73065 - Amanieu:tls-fix, r=oli-obk
Dylan-DPC Jun 13, 2020
58b2584
Rollup merge of #73086 - trevyn:apple-a7, r=nikic
Dylan-DPC Jun 13, 2020
23e7524
Rollup merge of #73267 - ehuss:cargotest-this-cargo, r=Mark-Simulacrum
Dylan-DPC Jun 13, 2020
bba35b1
Rollup merge of #73290 - LeSeulArtichaut:patch-1, r=Dylan-DPC
Dylan-DPC Jun 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/bootstrap/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl Step for Cargotest {
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(compile::Rustc { compiler, target: compiler.host });
let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });

// Note that this is a short, cryptic, and not scoped directory name. This
// is currently to minimize the length of path on Windows where we otherwise
Expand All @@ -165,7 +166,7 @@ impl Step for Cargotest {
let mut cmd = builder.tool_cmd(Tool::CargoTest);
try_run(
builder,
cmd.arg(&builder.initial_cargo)
cmd.arg(&cargo)
.arg(&out_dir)
.env("RUSTC", builder.rustc(compiler))
.env("RUSTDOC", builder.rustdoc(compiler)),
Expand Down
1 change: 1 addition & 0 deletions src/libcore/future/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
T: Generator<ResumeTy, Yield = ()>,
{
#[rustc_diagnostic_item = "gen_future"]
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);

// We rely on the fact that async/await futures are immovable in order to create
Expand Down
37 changes: 37 additions & 0 deletions src/libcore/str/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,43 @@ use crate::slice::memchr;
/// The trait itself acts as a builder for an associated
/// `Searcher` type, which does the actual work of finding
/// occurrences of the pattern in a string.
///
/// Depending on the type of the pattern, the behaviour of methods like
/// [`str::find`] and [`str::contains`] can change. The table below describes
/// some of those behaviours.
///
/// | Pattern type | Match condition |
/// |--------------------------|-------------------------------------------|
/// | `&str` | is substring |
/// | `char` | is contained in string |
/// | `&[char] | any char in slice is contained in string |
/// | `F: FnMut(char) -> bool` | `F` returns `true` for a char in string |
/// | `&&str` | is substring |
/// | `&String` | is substring |
///
/// # Examples
/// ```
/// // &str
/// assert_eq!("abaaa".find("ba"), Some(1));
/// assert_eq!("abaaa".find("bac"), None);
///
/// // char
/// assert_eq!("abaaa".find('a'), Some(0));
/// assert_eq!("abaaa".find('b'), Some(1));
/// assert_eq!("abaaa".find('c'), None);
///
/// // &[char]
/// assert_eq!("ab".find(&['b', 'a'][..]), Some(0));
/// assert_eq!("abaaa".find(&['a', 'z'][..]), Some(0));
/// assert_eq!("abaaa".find(&['c', 'd'][..]), None);
///
/// // FnMut(char) -> bool
/// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4));
/// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None);
/// ```
///
/// [`str::find`]: ../../../std/primitive.str.html#method.find
/// [`str::contains`]: ../../../std/primitive.str.html#method.contains
pub trait Pattern<'a>: Sized {
/// Associated searcher for this pattern
type Searcher: Searcher<'a>;
Expand Down
1 change: 1 addition & 0 deletions src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ E0752: include_str!("./error_codes/E0752.md"),
E0753: include_str!("./error_codes/E0753.md"),
E0754: include_str!("./error_codes/E0754.md"),
E0758: include_str!("./error_codes/E0758.md"),
E0759: include_str!("./error_codes/E0759.md"),
E0760: include_str!("./error_codes/E0760.md"),
E0761: include_str!("./error_codes/E0761.md"),
E0762: include_str!("./error_codes/E0762.md"),
Expand Down
67 changes: 67 additions & 0 deletions src/librustc_error_codes/error_codes/E0759.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
A `'static` requirement in a return type involving a trait is not fulfilled.

Erroneous code examples:

```compile_fail,E0759
use std::fmt::Debug;

fn foo(x: &i32) -> impl Debug {
x
}
```

```compile_fail,E0759
# use std::fmt::Debug;
fn bar(x: &i32) -> Box<dyn Debug> {
Box::new(x)
}
```

These examples have the same semantics as the following:

```compile_fail,E0759
# use std::fmt::Debug;
fn foo(x: &i32) -> impl Debug + 'static {
x
}
```

```compile_fail,E0759
# use std::fmt::Debug;
fn bar(x: &i32) -> Box<dyn Debug + 'static> {
Box::new(x)
}
```

Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit
`'static` requirement, meaning that the value implementing them that is being
returned has to be either a `'static` borrow or an owned value.

In order to change the requirement from `'static` to be a lifetime derived from
its arguments, you can add an explicit bound, either to an anonymous lifetime
`'_` or some appropriate named lifetime.

```
# use std::fmt::Debug;
fn foo(x: &i32) -> impl Debug + '_ {
x
}
fn bar(x: &i32) -> Box<dyn Debug + '_> {
Box::new(x)
}
```

These are equivalent to the following explicit lifetime annotations:

```
# use std::fmt::Debug;
fn foo<'a>(x: &'a i32) -> impl Debug + 'a {
x
}
fn bar<'a>(x: &'a i32) -> Box<dyn Debug + 'a> {
Box::new(x)
}
```

[`dyn Trait`]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits
3 changes: 1 addition & 2 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2037,8 +2037,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
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! 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};
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
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<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
if let Some(ref error) = self.error {
if let RegionResolutionError::SubSupConflict(
_,
Expand All @@ -17,18 +18,36 @@ 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)?;
let (fn_return_span, is_dyn) =
self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
if sub_r == &RegionKind::ReStatic {
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)?;
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 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...");
let (lifetime_name, lifetime) = if sup_r.has_name() {
(sup_r.to_string(), format!("lifetime `{}`", sup_r))
} else {
("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
};
let mut err = struct_span_err!(
self.tcx().sess,
sp,
E0759,
"cannot infer an appropriate 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.
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
Expand All @@ -38,41 +57,146 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {

// Customize the spans and labels depending on their relative order so
// that split sentences flow correctly.
if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() {
err.span_label(sup_origin.span(), "...is captured here...");
err.span_label(return_sp, "...and required to be `'static` by this");
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
// Avoid the following:
//
// error: cannot infer an appropriate lifetime
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
// |
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
// | ---- ---------^-
//
// and instead show:
//
// error: cannot infer an appropriate lifetime
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
// |
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
// | ---- ^
err.span_label(
sup_origin.span(),
"...is captured here, requiring it to live as long as `'static`",
);
} else {
err.span_label(return_sp, "...is required to be `'static` by this...");
err.span_label(sup_origin.span(), "...and is captured here");
err.span_label(sup_origin.span(), "...is captured here...");
if return_sp < sup_origin.span() {
err.span_note(
return_sp,
"...and is required to live as long as `'static` here",
);
} else {
err.span_label(
return_sp,
"...and is required to live as long as `'static` here",
);
}
}
} else {
err.span_label(
return_sp,
"...is captured and required to be `'static` here",
"...is captured and required to live as long as `'static` here",
);
}

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() {
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 + '_)`
err.span_suggestion_verbose(
fn_return_span.shrink_to_hi(),
&msg,
format!(" + {}", lifetime_name),
Applicability::MaybeIncorrect,
);

let consider = "consider changing the";
let declare = "to declare that the";
let arg = match param_info.param.pat.simple_ident() {
Some(simple_ident) => format!("argument `{}`", simple_ident),
None => "the argument".to_string(),
};
let explicit =
format!("you can add an explicit `{}` lifetime bound", lifetime_name);
let explicit_static =
format!("explicit `'static` bound to the lifetime of {}", arg);
let captures = format!("captures data from {}", arg);
let add_static_bound =
"alternatively, add an explicit `'static` bound to this reference";
let plus_lt = format!(" + {}", lifetime_name);
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);
};

if let Some(span) = opaque
.bounds
.iter()
.filter_map(|arg| match arg {
GenericBound::Outlives(Lifetime {
name: LifetimeName::Static,
span,
..
}) => Some(*span),
_ => None,
})
.next()
{
err.span_suggestion_verbose(
span,
&format!("{} `impl Trait`'s {}", consider, explicit_static),
lifetime_name,
Applicability::MaybeIncorrect,
);
err.span_suggestion_verbose(
param_info.param_ty_span,
add_static_bound,
param_info.param_ty.to_string(),
Applicability::MaybeIncorrect,
);
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
&format!(
"{declare} `impl Trait` {captures}, {explicit}",
declare = declare,
captures = captures,
explicit = explicit,
),
plus_lt,
Applicability::MaybeIncorrect,
);
};
}
TyKind::TraitObject(_, lt) => match lt.name {
LifetimeName::ImplicitObjectLifetimeDefault => {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
&format!(
"{declare} trait object {captures}, {explicit}",
declare = declare,
captures = captures,
explicit = explicit,
),
plus_lt,
Applicability::MaybeIncorrect,
);
}
_ => {
err.span_suggestion_verbose(
lt.span,
&format!("{} trait object's {}", consider, explicit_static),
lifetime_name,
Applicability::MaybeIncorrect,
);
err.span_suggestion_verbose(
param_info.param_ty_span,
add_static_bound,
param_info.param_ty.to_string(),
Applicability::MaybeIncorrect,
);
}
},
_ => {}
}
}
err.emit();
return Some(ErrorReported);
Expand Down
Loading