mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 23:12:02 +00:00
Auto merge of #48476 - Manishearth:rollup, r=Manishearth
Rollup of 12 pull requests - Successful merges: #47933, #48072, #48083, #48123, #48157, #48219, #48221, #48245, #48429, #48436, #48438, #48472 - Failed merges:
This commit is contained in:
commit
6070d3e47e
2
src/Cargo.lock
generated
2
src/Cargo.lock
generated
@ -1623,7 +1623,9 @@ dependencies = [
|
||||
"fmt_macros 0.0.0",
|
||||
"graphviz 0.0.0",
|
||||
"jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc_macro 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
|
@ -747,8 +747,8 @@ impl<T> LinkedList<T> {
|
||||
/// Creates an iterator which uses a closure to determine if an element should be removed.
|
||||
///
|
||||
/// If the closure returns true, then the element is removed and yielded.
|
||||
/// If the closure returns false, it will try again, and call the closure on the next element,
|
||||
/// seeing if it passes the test.
|
||||
/// If the closure returns false, the element will remain in the list and will not be yielded
|
||||
/// by the iterator.
|
||||
///
|
||||
/// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of
|
||||
/// whether you choose to keep or remove it.
|
||||
|
@ -364,7 +364,7 @@ impl String {
|
||||
///
|
||||
/// Given that the `String` is empty, this will not allocate any initial
|
||||
/// buffer. While that means that this initial operation is very
|
||||
/// inexpensive, but may cause excessive allocation later, when you add
|
||||
/// inexpensive, it may cause excessive allocation later when you add
|
||||
/// data. If you have an idea of how much data the `String` will hold,
|
||||
/// consider the [`with_capacity`] method to prevent excessive
|
||||
/// re-allocation.
|
||||
|
@ -1966,8 +1966,8 @@ impl<T> Vec<T> {
|
||||
/// Creates an iterator which uses a closure to determine if an element should be removed.
|
||||
///
|
||||
/// If the closure returns true, then the element is removed and yielded.
|
||||
/// If the closure returns false, it will try again, and call the closure
|
||||
/// on the next element, seeing if it passes the test.
|
||||
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
||||
/// by the iterator.
|
||||
///
|
||||
/// Using this method is equivalent to the following code:
|
||||
///
|
||||
|
@ -1366,9 +1366,9 @@ pub trait Iterator {
|
||||
///
|
||||
/// In particular, try to have this call `try_fold()` on the internal parts
|
||||
/// from which this iterator is composed. If multiple calls are needed,
|
||||
/// the `?` operator be convenient for chaining the accumulator value along,
|
||||
/// but beware any invariants that need to be upheld before those early
|
||||
/// returns. This is a `&mut self` method, so iteration needs to be
|
||||
/// the `?` operator may be convenient for chaining the accumulator value
|
||||
/// along, but beware any invariants that need to be upheld before those
|
||||
/// early returns. This is a `&mut self` method, so iteration needs to be
|
||||
/// resumable after hitting an error here.
|
||||
///
|
||||
/// # Examples
|
||||
@ -1414,6 +1414,42 @@ pub trait Iterator {
|
||||
Try::from_ok(accum)
|
||||
}
|
||||
|
||||
/// An iterator method that applies a fallible function to each item in the
|
||||
/// iterator, stopping at the first error and returning that error.
|
||||
///
|
||||
/// This can also be thought of as the fallible form of [`for_each()`]
|
||||
/// or as the stateless version of [`try_fold()`].
|
||||
///
|
||||
/// [`for_each()`]: #method.for_each
|
||||
/// [`try_fold()`]: #method.try_fold
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iterator_try_fold)]
|
||||
/// use std::fs::rename;
|
||||
/// use std::io::{stdout, Write};
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let data = ["no_tea.txt", "stale_bread.json", "torrential_rain.png"];
|
||||
///
|
||||
/// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{}", x));
|
||||
/// assert!(res.is_ok());
|
||||
///
|
||||
/// let mut it = data.iter().cloned();
|
||||
/// let res = it.try_for_each(|x| rename(x, Path::new(x).with_extension("old")));
|
||||
/// assert!(res.is_err());
|
||||
/// // It short-circuited, so the remaining items are still in the iterator:
|
||||
/// assert_eq!(it.next(), Some("stale_bread.json"));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iterator_try_fold", issue = "45594")]
|
||||
fn try_for_each<F, R>(&mut self, mut f: F) -> R where
|
||||
Self: Sized, F: FnMut(Self::Item) -> R, R: Try<Ok=()>
|
||||
{
|
||||
self.try_fold((), move |(), x| f(x))
|
||||
}
|
||||
|
||||
/// An iterator method that applies a function, producing a single, final value.
|
||||
///
|
||||
/// `fold()` takes two arguments: an initial value, and a closure with two
|
||||
@ -1532,7 +1568,7 @@ pub trait Iterator {
|
||||
fn all<F>(&mut self, mut f: F) -> bool where
|
||||
Self: Sized, F: FnMut(Self::Item) -> bool
|
||||
{
|
||||
self.try_fold((), move |(), x| {
|
||||
self.try_for_each(move |x| {
|
||||
if f(x) { LoopState::Continue(()) }
|
||||
else { LoopState::Break(()) }
|
||||
}) == LoopState::Continue(())
|
||||
@ -1581,7 +1617,7 @@ pub trait Iterator {
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item) -> bool
|
||||
{
|
||||
self.try_fold((), move |(), x| {
|
||||
self.try_for_each(move |x| {
|
||||
if f(x) { LoopState::Break(()) }
|
||||
else { LoopState::Continue(()) }
|
||||
}) == LoopState::Break(())
|
||||
@ -1635,7 +1671,7 @@ pub trait Iterator {
|
||||
Self: Sized,
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
self.try_fold((), move |(), x| {
|
||||
self.try_for_each(move |x| {
|
||||
if predicate(&x) { LoopState::Break(x) }
|
||||
else { LoopState::Continue(()) }
|
||||
}).break_value()
|
||||
|
@ -844,6 +844,12 @@ pub mod __internal {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn in_sess() -> bool
|
||||
{
|
||||
let p = CURRENT_SESS.with(|p| p.get());
|
||||
!p.0.is_null()
|
||||
}
|
||||
|
||||
pub fn with_sess<F, R>(f: F) -> R
|
||||
where F: FnOnce((&ParseSess, Mark)) -> R
|
||||
{
|
||||
|
@ -14,7 +14,9 @@ bitflags = "1.0"
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
jobserver = "0.1"
|
||||
lazy_static = "1.0.0"
|
||||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
proc_macro = { path = "../libproc_macro" }
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
|
@ -60,6 +60,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(quote)]
|
||||
#![feature(refcell_replace_swap)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
@ -81,6 +82,7 @@ extern crate core;
|
||||
extern crate fmt_macros;
|
||||
extern crate getopts;
|
||||
extern crate graphviz;
|
||||
#[macro_use] extern crate lazy_static;
|
||||
#[cfg(windows)]
|
||||
extern crate libc;
|
||||
extern crate rustc_back;
|
||||
@ -92,6 +94,7 @@ extern crate rustc_errors as errors;
|
||||
#[macro_use] extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
extern crate jobserver;
|
||||
extern crate proc_macro;
|
||||
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
|
@ -270,6 +270,19 @@ enum Scope<'a> {
|
||||
/// we should use for an early-bound region?
|
||||
next_early_index: u32,
|
||||
|
||||
/// Whether or not this binder would serve as the parent
|
||||
/// binder for abstract types introduced within. For example:
|
||||
///
|
||||
/// fn foo<'a>() -> impl for<'b> Trait<Item = impl Trait2<'a>>
|
||||
///
|
||||
/// Here, the abstract types we create for the `impl Trait`
|
||||
/// and `impl Trait2` references will both have the `foo` item
|
||||
/// as their parent. When we get to `impl Trait2`, we find
|
||||
/// that it is nested within the `for<>` binder -- this flag
|
||||
/// allows us to skip that when looking for the parent binder
|
||||
/// of the resulting abstract type.
|
||||
abstract_type_parent: bool,
|
||||
|
||||
s: ScopeRef<'a>,
|
||||
},
|
||||
|
||||
@ -498,6 +511,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
let scope = Scope::Binder {
|
||||
lifetimes,
|
||||
next_early_index,
|
||||
abstract_type_parent: true,
|
||||
s: ROOT_SCOPE,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
@ -541,6 +555,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
.collect(),
|
||||
s: self.scope,
|
||||
next_early_index,
|
||||
abstract_type_parent: false,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
// a bare fn has no bounds, so everything
|
||||
@ -614,7 +629,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
ref generics,
|
||||
ref bounds,
|
||||
} = *exist_ty;
|
||||
let mut index = self.next_early_index();
|
||||
|
||||
// We want to start our early-bound indices at the end of the parent scope,
|
||||
// not including any parent `impl Trait`s.
|
||||
let mut index = self.next_early_index_for_abstract_type();
|
||||
debug!("visit_ty: index = {}", index);
|
||||
|
||||
let mut elision = None;
|
||||
@ -638,7 +656,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
s: self.scope
|
||||
};
|
||||
self.with(scope, |_old_scope, this| {
|
||||
let scope = Scope::Binder { lifetimes, next_early_index, s: this.scope };
|
||||
let scope = Scope::Binder {
|
||||
lifetimes,
|
||||
next_early_index,
|
||||
s: this.scope,
|
||||
abstract_type_parent: false,
|
||||
};
|
||||
this.with(scope, |_old_scope, this| {
|
||||
this.visit_generics(generics);
|
||||
for bound in bounds {
|
||||
@ -647,7 +670,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
|
||||
let scope = Scope::Binder {
|
||||
lifetimes,
|
||||
next_early_index,
|
||||
s: self.scope,
|
||||
abstract_type_parent: false,
|
||||
};
|
||||
self.with(scope, |_old_scope, this| {
|
||||
this.visit_generics(generics);
|
||||
for bound in bounds {
|
||||
@ -681,7 +709,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
.collect();
|
||||
|
||||
let next_early_index = index + generics.ty_params().count() as u32;
|
||||
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
|
||||
let scope = Scope::Binder {
|
||||
lifetimes,
|
||||
next_early_index,
|
||||
s: self.scope,
|
||||
abstract_type_parent: true,
|
||||
};
|
||||
self.with(scope, |_old_scope, this| {
|
||||
this.visit_generics(generics);
|
||||
for bound in bounds {
|
||||
@ -721,7 +754,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
.collect();
|
||||
|
||||
let next_early_index = index + generics.ty_params().count() as u32;
|
||||
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
|
||||
let scope = Scope::Binder {
|
||||
lifetimes,
|
||||
next_early_index,
|
||||
s: self.scope,
|
||||
abstract_type_parent: true,
|
||||
};
|
||||
self.with(scope, |_old_scope, this| {
|
||||
this.visit_generics(generics);
|
||||
this.visit_ty(ty);
|
||||
@ -792,6 +830,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
.collect(),
|
||||
s: self.scope,
|
||||
next_early_index,
|
||||
abstract_type_parent: false,
|
||||
};
|
||||
let result = self.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &bound_generic_params);
|
||||
@ -853,6 +892,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
.collect(),
|
||||
s: self.scope,
|
||||
next_early_index,
|
||||
abstract_type_parent: false,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
|
||||
@ -1046,6 +1086,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
|
||||
ref lifetimes,
|
||||
s,
|
||||
next_early_index: _,
|
||||
abstract_type_parent: _,
|
||||
} => {
|
||||
// FIXME (#24278): non-hygienic comparison
|
||||
if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
|
||||
@ -1303,6 +1344,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
lifetimes,
|
||||
next_early_index,
|
||||
s: self.scope,
|
||||
abstract_type_parent: true,
|
||||
};
|
||||
self.with(scope, move |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &generics.params);
|
||||
@ -1310,25 +1352,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the next index one would use for an early-bound-region
|
||||
/// if extending the current scope.
|
||||
fn next_early_index(&self) -> u32 {
|
||||
fn next_early_index_helper(&self, only_abstract_type_parent: bool) -> u32 {
|
||||
let mut scope = self.scope;
|
||||
loop {
|
||||
match *scope {
|
||||
Scope::Root => return 0,
|
||||
|
||||
Scope::Binder {
|
||||
next_early_index, ..
|
||||
} => return next_early_index,
|
||||
next_early_index,
|
||||
abstract_type_parent,
|
||||
..
|
||||
} if (!only_abstract_type_parent || abstract_type_parent)
|
||||
=> return next_early_index,
|
||||
|
||||
Scope::Body { s, .. }
|
||||
Scope::Binder { s, .. }
|
||||
| Scope::Body { s, .. }
|
||||
| Scope::Elision { s, .. }
|
||||
| Scope::ObjectLifetimeDefault { s, .. } => scope = s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next index one would use for an early-bound-region
|
||||
/// if extending the current scope.
|
||||
fn next_early_index(&self) -> u32 {
|
||||
self.next_early_index_helper(true)
|
||||
}
|
||||
|
||||
/// Returns the next index one would use for an `impl Trait` that
|
||||
/// is being converted into an `abstract type`. This will be the
|
||||
/// next early index from the enclosing item, for the most
|
||||
/// part. See the `abstract_type_parent` field for more info.
|
||||
fn next_early_index_for_abstract_type(&self) -> u32 {
|
||||
self.next_early_index_helper(false)
|
||||
}
|
||||
|
||||
fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
|
||||
// Walk up the scope chain, tracking the number of fn scopes
|
||||
@ -1353,6 +1411,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
ref lifetimes,
|
||||
s,
|
||||
next_early_index: _,
|
||||
abstract_type_parent: _,
|
||||
} => {
|
||||
if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
|
||||
break Some(def.shifted(late_depth));
|
||||
@ -2102,6 +2161,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
ref lifetimes,
|
||||
s,
|
||||
next_early_index: _,
|
||||
abstract_type_parent: _,
|
||||
} => {
|
||||
if let Some(&def) = lifetimes.get(&lifetime.name) {
|
||||
let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
|
||||
|
@ -747,7 +747,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::TyTuple(ref tys, _) => tys.iter()
|
||||
.map(|t| match t.sty {
|
||||
ty::TypeVariants::TyTuple(ref tys, _) => ArgKind::Tuple(
|
||||
span,
|
||||
Some(span),
|
||||
tys.iter()
|
||||
.map(|ty| ("_".to_owned(), format!("{}", ty.sty)))
|
||||
.collect::<Vec<_>>()
|
||||
@ -815,7 +815,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec<ArgKind>) {
|
||||
/// Given some node representing a fn-like thing in the HIR map,
|
||||
/// returns a span and `ArgKind` information that describes the
|
||||
/// arguments it expects. This can be supplied to
|
||||
/// `report_arg_count_mismatch`.
|
||||
pub fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec<ArgKind>) {
|
||||
match node {
|
||||
hir::map::NodeExpr(&hir::Expr {
|
||||
node: hir::ExprClosure(_, ref _decl, id, span, _),
|
||||
@ -829,7 +833,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
..
|
||||
} = arg.pat.clone().into_inner() {
|
||||
ArgKind::Tuple(
|
||||
span,
|
||||
Some(span),
|
||||
args.iter().map(|pat| {
|
||||
let snippet = self.tcx.sess.codemap()
|
||||
.span_to_snippet(pat.span).unwrap();
|
||||
@ -862,7 +866,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
(self.tcx.sess.codemap().def_span(span), decl.inputs.iter()
|
||||
.map(|arg| match arg.clone().into_inner().node {
|
||||
hir::TyTup(ref tys) => ArgKind::Tuple(
|
||||
arg.span,
|
||||
Some(arg.span),
|
||||
tys.iter()
|
||||
.map(|_| ("_".to_owned(), "_".to_owned()))
|
||||
.collect::<Vec<_>>(),
|
||||
@ -874,7 +878,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn report_arg_count_mismatch(
|
||||
/// Reports an error when the number of arguments needed by a
|
||||
/// trait match doesn't match the number that the expression
|
||||
/// provides.
|
||||
pub fn report_arg_count_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
@ -1385,13 +1392,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
enum ArgKind {
|
||||
/// Summarizes information
|
||||
pub enum ArgKind {
|
||||
/// An argument of non-tuple type. Parameters are (name, ty)
|
||||
Arg(String, String),
|
||||
Tuple(Span, Vec<(String, String)>),
|
||||
|
||||
/// An argument of tuple type. For a "found" argument, the span is
|
||||
/// the locationo in the source of the pattern. For a "expected"
|
||||
/// argument, it will be None. The vector is a list of (name, ty)
|
||||
/// strings for the components of the tuple.
|
||||
Tuple(Option<Span>, Vec<(String, String)>),
|
||||
}
|
||||
|
||||
impl ArgKind {
|
||||
fn empty() -> ArgKind {
|
||||
ArgKind::Arg("_".to_owned(), "_".to_owned())
|
||||
}
|
||||
|
||||
/// Creates an `ArgKind` from the expected type of an
|
||||
/// argument. This has no name (`_`) and no source spans..
|
||||
pub fn from_expected_ty(t: Ty<'_>) -> ArgKind {
|
||||
match t.sty {
|
||||
ty::TyTuple(ref tys, _) => ArgKind::Tuple(
|
||||
None,
|
||||
tys.iter()
|
||||
.map(|ty| ("_".to_owned(), format!("{}", ty.sty)))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
_ => ArgKind::Arg("_".to_owned(), format!("{}", t.sty)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ pub use self::util::SupertraitDefIds;
|
||||
pub use self::util::transitive_bounds;
|
||||
|
||||
mod coherence;
|
||||
mod error_reporting;
|
||||
pub mod error_reporting;
|
||||
mod fulfill;
|
||||
mod project;
|
||||
mod object_safety;
|
||||
|
@ -16,6 +16,7 @@ use std::ffi::CString;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{Hash, BuildHasher};
|
||||
use std::iter::repeat;
|
||||
use std::panic;
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@ -23,6 +24,8 @@ use std::sync::mpsc::{Sender};
|
||||
use syntax_pos::{SpanData};
|
||||
use ty::maps::{QueryMsg};
|
||||
use dep_graph::{DepNode};
|
||||
use proc_macro;
|
||||
use lazy_static;
|
||||
|
||||
// The name of the associated type for `Fn` return types
|
||||
pub const FN_OUTPUT_NAME: &'static str = "Output";
|
||||
@ -34,6 +37,24 @@ pub struct ErrorReported;
|
||||
|
||||
thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
|
||||
|
||||
lazy_static! {
|
||||
static ref DEFAULT_HOOK: Box<Fn(&panic::PanicInfo) + Sync + Send + 'static> = {
|
||||
let hook = panic::take_hook();
|
||||
panic::set_hook(Box::new(panic_hook));
|
||||
hook
|
||||
};
|
||||
}
|
||||
|
||||
fn panic_hook(info: &panic::PanicInfo) {
|
||||
if !proc_macro::__internal::in_sess() {
|
||||
(*DEFAULT_HOOK)(info)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_panic_hook() {
|
||||
lazy_static::initialize(&DEFAULT_HOOK);
|
||||
}
|
||||
|
||||
/// Initialized for -Z profile-queries
|
||||
thread_local!(static PROFQ_CHAN: RefCell<Option<Sender<ProfileQueriesMsg>>> = RefCell::new(None));
|
||||
|
||||
|
@ -8,19 +8,28 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::marker::PhantomData;
|
||||
use std::iter::FromIterator;
|
||||
use indexed_vec::{Idx, IndexVec};
|
||||
|
||||
type Word = u128;
|
||||
const WORD_BITS: usize = 128;
|
||||
|
||||
/// A very simple BitVector type.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct BitVector {
|
||||
data: Vec<u64>,
|
||||
data: Vec<Word>,
|
||||
}
|
||||
|
||||
impl BitVector {
|
||||
#[inline]
|
||||
pub fn new(num_bits: usize) -> BitVector {
|
||||
let num_words = u64s(num_bits);
|
||||
BitVector { data: vec![0; num_words] }
|
||||
let num_words = words(num_bits);
|
||||
BitVector {
|
||||
data: vec![0; num_words],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -78,7 +87,7 @@ impl BitVector {
|
||||
|
||||
#[inline]
|
||||
pub fn grow(&mut self, num_bits: usize) {
|
||||
let num_words = u64s(num_bits);
|
||||
let num_words = words(num_bits);
|
||||
if self.data.len() < num_words {
|
||||
self.data.resize(num_words, 0)
|
||||
}
|
||||
@ -96,8 +105,8 @@ impl BitVector {
|
||||
}
|
||||
|
||||
pub struct BitVectorIter<'a> {
|
||||
iter: ::std::slice::Iter<'a, u64>,
|
||||
current: u64,
|
||||
iter: ::std::slice::Iter<'a, Word>,
|
||||
current: Word,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
@ -107,10 +116,10 @@ impl<'a> Iterator for BitVectorIter<'a> {
|
||||
while self.current == 0 {
|
||||
self.current = if let Some(&i) = self.iter.next() {
|
||||
if i == 0 {
|
||||
self.idx += 64;
|
||||
self.idx += WORD_BITS;
|
||||
continue;
|
||||
} else {
|
||||
self.idx = u64s(self.idx) * 64;
|
||||
self.idx = words(self.idx) * WORD_BITS;
|
||||
i
|
||||
}
|
||||
} else {
|
||||
@ -126,12 +135,15 @@ impl<'a> Iterator for BitVectorIter<'a> {
|
||||
}
|
||||
|
||||
impl FromIterator<bool> for BitVector {
|
||||
fn from_iter<I>(iter: I) -> BitVector where I: IntoIterator<Item=bool> {
|
||||
fn from_iter<I>(iter: I) -> BitVector
|
||||
where
|
||||
I: IntoIterator<Item = bool>,
|
||||
{
|
||||
let iter = iter.into_iter();
|
||||
let (len, _) = iter.size_hint();
|
||||
// Make the minimum length for the bitvector 64 bits since that's
|
||||
// Make the minimum length for the bitvector WORD_BITS bits since that's
|
||||
// the smallest non-zero size anyway.
|
||||
let len = if len < 64 { 64 } else { len };
|
||||
let len = if len < WORD_BITS { WORD_BITS } else { len };
|
||||
let mut bv = BitVector::new(len);
|
||||
for (idx, val) in iter.enumerate() {
|
||||
if idx > len {
|
||||
@ -152,32 +164,32 @@ impl FromIterator<bool> for BitVector {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BitMatrix {
|
||||
columns: usize,
|
||||
vector: Vec<u64>,
|
||||
vector: Vec<Word>,
|
||||
}
|
||||
|
||||
impl BitMatrix {
|
||||
/// Create a new `rows x columns` matrix, initially empty.
|
||||
pub fn new(rows: usize, columns: usize) -> BitMatrix {
|
||||
// For every element, we need one bit for every other
|
||||
// element. Round up to an even number of u64s.
|
||||
let u64s_per_row = u64s(columns);
|
||||
// element. Round up to an even number of words.
|
||||
let words_per_row = words(columns);
|
||||
BitMatrix {
|
||||
columns,
|
||||
vector: vec![0; rows * u64s_per_row],
|
||||
vector: vec![0; rows * words_per_row],
|
||||
}
|
||||
}
|
||||
|
||||
/// The range of bits for a given row.
|
||||
fn range(&self, row: usize) -> (usize, usize) {
|
||||
let u64s_per_row = u64s(self.columns);
|
||||
let start = row * u64s_per_row;
|
||||
(start, start + u64s_per_row)
|
||||
let words_per_row = words(self.columns);
|
||||
let start = row * words_per_row;
|
||||
(start, start + words_per_row)
|
||||
}
|
||||
|
||||
/// Sets the cell at `(row, column)` to true. Put another way, add
|
||||
/// `column` to the bitset for `row`.
|
||||
///
|
||||
/// Returns true if this changed the matrix, and false otherwies.
|
||||
/// Returns true if this changed the matrix, and false otherwise.
|
||||
pub fn add(&mut self, row: usize, column: usize) -> bool {
|
||||
let (start, _) = self.range(row);
|
||||
let (word, mask) = word_mask(column);
|
||||
@ -208,12 +220,12 @@ impl BitMatrix {
|
||||
let mut result = Vec::with_capacity(self.columns);
|
||||
for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
|
||||
let mut v = self.vector[i] & self.vector[j];
|
||||
for bit in 0..64 {
|
||||
for bit in 0..WORD_BITS {
|
||||
if v == 0 {
|
||||
break;
|
||||
}
|
||||
if v & 0x1 != 0 {
|
||||
result.push(base * 64 + bit);
|
||||
result.push(base * WORD_BITS + bit);
|
||||
}
|
||||
v >>= 1;
|
||||
}
|
||||
@ -254,15 +266,214 @@ impl BitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn u64s(elements: usize) -> usize {
|
||||
(elements + 63) / 64
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SparseBitMatrix<R, C>
|
||||
where
|
||||
R: Idx,
|
||||
C: Idx,
|
||||
{
|
||||
vector: IndexVec<R, SparseBitSet<C>>,
|
||||
}
|
||||
|
||||
impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
|
||||
/// Create a new `rows x columns` matrix, initially empty.
|
||||
pub fn new(rows: R, _columns: C) -> SparseBitMatrix<R, C> {
|
||||
SparseBitMatrix {
|
||||
vector: IndexVec::from_elem_n(SparseBitSet::new(), rows.index()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the cell at `(row, column)` to true. Put another way, insert
|
||||
/// `column` to the bitset for `row`.
|
||||
///
|
||||
/// Returns true if this changed the matrix, and false otherwise.
|
||||
pub fn add(&mut self, row: R, column: C) -> bool {
|
||||
self.vector[row].insert(column)
|
||||
}
|
||||
|
||||
/// Do the bits from `row` contain `column`? Put another way, is
|
||||
/// the matrix cell at `(row, column)` true? Put yet another way,
|
||||
/// if the matrix represents (transitive) reachability, can
|
||||
/// `row` reach `column`?
|
||||
pub fn contains(&self, row: R, column: C) -> bool {
|
||||
self.vector[row].contains(column)
|
||||
}
|
||||
|
||||
/// Add the bits from row `read` to the bits from row `write`,
|
||||
/// return true if anything changed.
|
||||
///
|
||||
/// This is used when computing transitive reachability because if
|
||||
/// you have an edge `write -> read`, because in that case
|
||||
/// `write` can reach everything that `read` can (and
|
||||
/// potentially more).
|
||||
pub fn merge(&mut self, read: R, write: R) -> bool {
|
||||
let mut changed = false;
|
||||
|
||||
if read != write {
|
||||
let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
|
||||
|
||||
for read_val in bit_set_read.iter() {
|
||||
changed = changed | bit_set_write.insert(read_val);
|
||||
}
|
||||
}
|
||||
|
||||
changed
|
||||
}
|
||||
|
||||
/// Iterates through all the columns set to true in a given row of
|
||||
/// the matrix.
|
||||
pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
|
||||
self.vector[row].iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SparseBitSet<I: Idx> {
|
||||
chunk_bits: BTreeMap<u32, Word>,
|
||||
_marker: PhantomData<I>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SparseChunk<I> {
|
||||
key: u32,
|
||||
bits: Word,
|
||||
_marker: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: Idx> SparseChunk<I> {
|
||||
pub fn one(index: I) -> Self {
|
||||
let index = index.index();
|
||||
let key_usize = index / 128;
|
||||
let key = key_usize as u32;
|
||||
assert_eq!(key as usize, key_usize);
|
||||
SparseChunk {
|
||||
key,
|
||||
bits: 1 << (index % 128),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn any(&self) -> bool {
|
||||
self.bits != 0
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = I> {
|
||||
let base = self.key as usize * 128;
|
||||
let mut bits = self.bits;
|
||||
(0..128)
|
||||
.map(move |i| {
|
||||
let current_bits = bits;
|
||||
bits >>= 1;
|
||||
(i, current_bits)
|
||||
})
|
||||
.take_while(|&(_, bits)| bits != 0)
|
||||
.filter_map(move |(i, bits)| {
|
||||
if (bits & 1) != 0 {
|
||||
Some(I::new(base + i))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Idx> SparseBitSet<I> {
|
||||
pub fn new() -> Self {
|
||||
SparseBitSet {
|
||||
chunk_bits: BTreeMap::new(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.chunk_bits.len() * 128
|
||||
}
|
||||
|
||||
pub fn contains_chunk(&self, chunk: SparseChunk<I>) -> SparseChunk<I> {
|
||||
SparseChunk {
|
||||
bits: self.chunk_bits
|
||||
.get(&chunk.key)
|
||||
.map_or(0, |bits| bits & chunk.bits),
|
||||
..chunk
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_chunk(&mut self, chunk: SparseChunk<I>) -> SparseChunk<I> {
|
||||
if chunk.bits == 0 {
|
||||
return chunk;
|
||||
}
|
||||
let bits = self.chunk_bits.entry(chunk.key).or_insert(0);
|
||||
let old_bits = *bits;
|
||||
let new_bits = old_bits | chunk.bits;
|
||||
*bits = new_bits;
|
||||
let changed = new_bits ^ old_bits;
|
||||
SparseChunk {
|
||||
bits: changed,
|
||||
..chunk
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_chunk(&mut self, chunk: SparseChunk<I>) -> SparseChunk<I> {
|
||||
if chunk.bits == 0 {
|
||||
return chunk;
|
||||
}
|
||||
let changed = match self.chunk_bits.entry(chunk.key) {
|
||||
Entry::Occupied(mut bits) => {
|
||||
let old_bits = *bits.get();
|
||||
let new_bits = old_bits & !chunk.bits;
|
||||
if new_bits == 0 {
|
||||
bits.remove();
|
||||
} else {
|
||||
bits.insert(new_bits);
|
||||
}
|
||||
new_bits ^ old_bits
|
||||
}
|
||||
Entry::Vacant(_) => 0,
|
||||
};
|
||||
SparseChunk {
|
||||
bits: changed,
|
||||
..chunk
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.chunk_bits.clear();
|
||||
}
|
||||
|
||||
pub fn chunks<'a>(&'a self) -> impl Iterator<Item = SparseChunk<I>> + 'a {
|
||||
self.chunk_bits.iter().map(|(&key, &bits)| SparseChunk {
|
||||
key,
|
||||
bits,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn contains(&self, index: I) -> bool {
|
||||
self.contains_chunk(SparseChunk::one(index)).any()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, index: I) -> bool {
|
||||
self.insert_chunk(SparseChunk::one(index)).any()
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, index: I) -> bool {
|
||||
self.remove_chunk(SparseChunk::one(index)).any()
|
||||
}
|
||||
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = I> + 'a {
|
||||
self.chunks().flat_map(|chunk| chunk.iter())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn word_mask(index: usize) -> (usize, u64) {
|
||||
let word = index / 64;
|
||||
let mask = 1 << (index % 64);
|
||||
fn words(elements: usize) -> usize {
|
||||
(elements + WORD_BITS - 1) / WORD_BITS
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn word_mask(index: usize) -> (usize, Word) {
|
||||
let word = index / WORD_BITS;
|
||||
let mask = 1 << (index % WORD_BITS);
|
||||
(word, mask)
|
||||
}
|
||||
|
||||
@ -278,11 +489,12 @@ fn bitvec_iter_works() {
|
||||
bitvec.insert(65);
|
||||
bitvec.insert(66);
|
||||
bitvec.insert(99);
|
||||
assert_eq!(bitvec.iter().collect::<Vec<_>>(),
|
||||
[1, 10, 19, 62, 63, 64, 65, 66, 99]);
|
||||
assert_eq!(
|
||||
bitvec.iter().collect::<Vec<_>>(),
|
||||
[1, 10, 19, 62, 63, 64, 65, 66, 99]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn bitvec_iter_works_2() {
|
||||
let mut bitvec = BitVector::new(319);
|
||||
@ -314,24 +526,24 @@ fn union_two_vecs() {
|
||||
#[test]
|
||||
fn grow() {
|
||||
let mut vec1 = BitVector::new(65);
|
||||
for index in 0 .. 65 {
|
||||
for index in 0..65 {
|
||||
assert!(vec1.insert(index));
|
||||
assert!(!vec1.insert(index));
|
||||
}
|
||||
vec1.grow(128);
|
||||
|
||||
// Check if the bits set before growing are still set
|
||||
for index in 0 .. 65 {
|
||||
for index in 0..65 {
|
||||
assert!(vec1.contains(index));
|
||||
}
|
||||
|
||||
// Check if the new bits are all un-set
|
||||
for index in 65 .. 128 {
|
||||
for index in 65..128 {
|
||||
assert!(!vec1.contains(index));
|
||||
}
|
||||
|
||||
// Check that we can set all new bits without running out of bounds
|
||||
for index in 65 .. 128 {
|
||||
for index in 65..128 {
|
||||
assert!(vec1.insert(index));
|
||||
assert!(!vec1.insert(index));
|
||||
}
|
||||
|
@ -482,6 +482,21 @@ impl<I: Idx, T> IndexVec<I, T> {
|
||||
pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
|
||||
self.raw.get_mut(index.index())
|
||||
}
|
||||
|
||||
/// Return mutable references to two distinct elements, a and b. Panics if a == b.
|
||||
#[inline]
|
||||
pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
|
||||
let (ai, bi) = (a.index(), b.index());
|
||||
assert!(ai != bi);
|
||||
|
||||
if ai < bi {
|
||||
let (c1, c2) = self.raw.split_at_mut(bi);
|
||||
(&mut c1[ai], &mut c2[0])
|
||||
} else {
|
||||
let (c2, c1) = self.pick2_mut(b, a);
|
||||
(c1, c2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Idx, T: Clone> IndexVec<I, T> {
|
||||
|
@ -24,7 +24,7 @@ use rustc::middle::cstore::CrateStore;
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
|
||||
use rustc::traits;
|
||||
use rustc::util::common::{ErrorReported, time};
|
||||
use rustc::util::common::{ErrorReported, time, install_panic_hook};
|
||||
use rustc_allocator as allocator;
|
||||
use rustc_borrowck as borrowck;
|
||||
use rustc_incremental;
|
||||
@ -123,6 +123,8 @@ pub fn compile_input(trans: Box<TransCrate>,
|
||||
let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
|
||||
let crate_name =
|
||||
::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
|
||||
install_panic_hook();
|
||||
|
||||
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
|
||||
phase_2_configure_and_expand(
|
||||
sess,
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
@ -26,7 +25,6 @@ use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::attr;
|
||||
use syntax_pos::Span;
|
||||
use syntax::codemap;
|
||||
|
||||
@ -353,13 +351,14 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
|
||||
cx: &'a LateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
enum FfiResult {
|
||||
enum FfiResult<'tcx> {
|
||||
FfiSafe,
|
||||
FfiPhantom,
|
||||
FfiUnsafe(&'static str),
|
||||
FfiBadStruct(DefId, &'static str),
|
||||
FfiBadUnion(DefId, &'static str),
|
||||
FfiBadEnum(DefId, &'static str),
|
||||
FfiPhantom(Ty<'tcx>),
|
||||
FfiUnsafe {
|
||||
ty: Ty<'tcx>,
|
||||
reason: &'static str,
|
||||
help: Option<&'static str>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Check if this enum can be safely exported based on the
|
||||
@ -397,23 +396,12 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
false
|
||||
}
|
||||
|
||||
fn is_ffi_safe(ty: attr::IntType) -> bool {
|
||||
match ty {
|
||||
attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
|
||||
attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
|
||||
attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
|
||||
attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
|
||||
attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
|
||||
attr::SignedInt(ast::IntTy::Isize) | attr::UnsignedInt(ast::UintTy::Usize) => false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
/// Check if the given type is "ffi-safe" (has a stable, well-defined
|
||||
/// representation which can be exported to C code).
|
||||
fn check_type_for_ffi(&self,
|
||||
cache: &mut FxHashSet<Ty<'tcx>>,
|
||||
ty: Ty<'tcx>) -> FfiResult {
|
||||
ty: Ty<'tcx>) -> FfiResult<'tcx> {
|
||||
use self::FfiResult::*;
|
||||
|
||||
let cx = self.cx.tcx;
|
||||
@ -429,19 +417,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, substs) => {
|
||||
if def.is_phantom_data() {
|
||||
return FfiPhantom;
|
||||
return FfiPhantom(ty);
|
||||
}
|
||||
match def.adt_kind() {
|
||||
AdtKind::Struct => {
|
||||
if !def.repr.c() && !def.repr.transparent() {
|
||||
return FfiUnsafe("found struct without foreign-function-safe \
|
||||
representation annotation in foreign module, \
|
||||
consider adding a #[repr(C)] attribute to the type");
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "this struct has unspecified layout",
|
||||
help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \
|
||||
attribute to this struct"),
|
||||
};
|
||||
}
|
||||
|
||||
if def.non_enum_variant().fields.is_empty() {
|
||||
return FfiUnsafe("found zero-size struct in foreign module, consider \
|
||||
adding a member to this struct");
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "this struct has no fields",
|
||||
help: Some("consider adding a member to this struct"),
|
||||
};
|
||||
}
|
||||
|
||||
// We can't completely trust repr(C) and repr(transparent) markings;
|
||||
@ -467,28 +461,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
FfiSafe => {
|
||||
all_phantom = false;
|
||||
}
|
||||
FfiPhantom => {}
|
||||
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
|
||||
FfiPhantom(..) => {}
|
||||
FfiUnsafe { .. } => {
|
||||
return r;
|
||||
}
|
||||
FfiUnsafe(s) => {
|
||||
return FfiBadStruct(def.did, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if all_phantom { FfiPhantom } else { FfiSafe }
|
||||
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
|
||||
}
|
||||
AdtKind::Union => {
|
||||
if !def.repr.c() {
|
||||
return FfiUnsafe("found union without foreign-function-safe \
|
||||
representation annotation in foreign module, \
|
||||
consider adding a #[repr(C)] attribute to the type");
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "this union has unspecified layout",
|
||||
help: Some("consider adding a #[repr(C)] attribute to this union"),
|
||||
};
|
||||
}
|
||||
|
||||
if def.non_enum_variant().fields.is_empty() {
|
||||
return FfiUnsafe("found zero-size union in foreign module, consider \
|
||||
adding a member to this union");
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "this union has no fields",
|
||||
help: Some("consider adding a field to this union"),
|
||||
};
|
||||
}
|
||||
|
||||
let mut all_phantom = true;
|
||||
@ -501,17 +497,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
FfiSafe => {
|
||||
all_phantom = false;
|
||||
}
|
||||
FfiPhantom => {}
|
||||
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
|
||||
FfiPhantom(..) => {}
|
||||
FfiUnsafe { .. } => {
|
||||
return r;
|
||||
}
|
||||
FfiUnsafe(s) => {
|
||||
return FfiBadUnion(def.did, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if all_phantom { FfiPhantom } else { FfiSafe }
|
||||
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
|
||||
}
|
||||
AdtKind::Enum => {
|
||||
if def.variants.is_empty() {
|
||||
@ -524,27 +517,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
if !def.repr.c() && def.repr.int.is_none() {
|
||||
// Special-case types like `Option<extern fn()>`.
|
||||
if !is_repr_nullable_ptr(cx, def, substs) {
|
||||
return FfiUnsafe("found enum without foreign-function-safe \
|
||||
representation annotation in foreign \
|
||||
module, consider adding a #[repr(...)] \
|
||||
attribute to the type");
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "enum has no representation hint",
|
||||
help: Some("consider adding a #[repr(...)] attribute \
|
||||
to this enum"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(int_ty) = def.repr.int {
|
||||
if !is_ffi_safe(int_ty) {
|
||||
// FIXME: This shouldn't be reachable: we should check
|
||||
// this earlier.
|
||||
return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
|
||||
}
|
||||
|
||||
// Enum with an explicitly sized discriminant; either
|
||||
// a C-style enum or a discriminated union.
|
||||
|
||||
// The layout of enum variants is implicitly repr(C).
|
||||
// FIXME: Is that correct?
|
||||
}
|
||||
|
||||
// Check the contained variants.
|
||||
for variant in &def.variants {
|
||||
for field in &variant.fields {
|
||||
@ -554,15 +535,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
let r = self.check_type_for_ffi(cache, arg);
|
||||
match r {
|
||||
FfiSafe => {}
|
||||
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
|
||||
FfiUnsafe { .. } => {
|
||||
return r;
|
||||
}
|
||||
FfiPhantom => {
|
||||
return FfiBadEnum(def.did,
|
||||
"Found phantom data in enum variant");
|
||||
}
|
||||
FfiUnsafe(s) => {
|
||||
return FfiBadEnum(def.did, s);
|
||||
FfiPhantom(..) => {
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "this enum contains a PhantomData field",
|
||||
help: None,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -572,45 +553,44 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyChar => {
|
||||
FfiUnsafe("found Rust type `char` in foreign module, while \
|
||||
`u32` or `libc::wchar_t` should be used")
|
||||
}
|
||||
ty::TyChar => FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "the `char` type has no C equivalent",
|
||||
help: Some("consider using `u32` or `libc::wchar_t` instead"),
|
||||
},
|
||||
|
||||
ty::TyInt(ast::IntTy::I128) => {
|
||||
FfiUnsafe("found Rust type `i128` in foreign module, but \
|
||||
128-bit integers don't currently have a known \
|
||||
stable ABI")
|
||||
}
|
||||
|
||||
ty::TyUint(ast::UintTy::U128) => {
|
||||
FfiUnsafe("found Rust type `u128` in foreign module, but \
|
||||
128-bit integers don't currently have a known \
|
||||
stable ABI")
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I128) | ty::TyUint(ast::UintTy::U128) => FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "128-bit integers don't currently have a known stable ABI",
|
||||
help: None,
|
||||
},
|
||||
|
||||
// Primitive types with a stable representation.
|
||||
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
|
||||
|
||||
ty::TySlice(_) => {
|
||||
FfiUnsafe("found Rust slice type in foreign module, \
|
||||
consider using a raw pointer instead")
|
||||
}
|
||||
ty::TySlice(_) => FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "slices have no C equivalent",
|
||||
help: Some("consider using a raw pointer instead"),
|
||||
},
|
||||
|
||||
ty::TyDynamic(..) => {
|
||||
FfiUnsafe("found Rust trait type in foreign module, \
|
||||
consider using a raw pointer instead")
|
||||
}
|
||||
ty::TyDynamic(..) => FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "trait objects have no C equivalent",
|
||||
help: None,
|
||||
},
|
||||
|
||||
ty::TyStr => {
|
||||
FfiUnsafe("found Rust type `str` in foreign module; \
|
||||
consider using a `*const libc::c_char`")
|
||||
}
|
||||
ty::TyStr => FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "string slices have no C equivalent",
|
||||
help: Some("consider using `*const u8` and a length instead"),
|
||||
},
|
||||
|
||||
ty::TyTuple(..) => {
|
||||
FfiUnsafe("found Rust tuple type in foreign module; \
|
||||
consider using a struct instead")
|
||||
}
|
||||
ty::TyTuple(..) => FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "tuples have unspecified layout",
|
||||
help: Some("consider using a struct instead"),
|
||||
},
|
||||
|
||||
ty::TyRawPtr(ref m) |
|
||||
ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
|
||||
@ -620,9 +600,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
ty::TyFnPtr(sig) => {
|
||||
match sig.abi() {
|
||||
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
|
||||
return FfiUnsafe("found function pointer with Rust calling convention in \
|
||||
foreign module; consider using an `extern` function \
|
||||
pointer")
|
||||
return FfiUnsafe {
|
||||
ty: ty,
|
||||
reason: "this function pointer has Rust-specific calling convention",
|
||||
help: Some("consider using an `fn \"extern\"(...) -> ...` \
|
||||
function pointer instead"),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -670,40 +653,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
|
||||
match self.check_type_for_ffi(&mut FxHashSet(), ty) {
|
||||
FfiResult::FfiSafe => {}
|
||||
FfiResult::FfiPhantom => {
|
||||
FfiResult::FfiPhantom(ty) => {
|
||||
self.cx.span_lint(IMPROPER_CTYPES,
|
||||
sp,
|
||||
&format!("found zero-sized type composed only \
|
||||
of phantom-data in a foreign-function."));
|
||||
&format!("`extern` block uses type `{}` which is not FFI-safe: \
|
||||
composed only of PhantomData", ty));
|
||||
}
|
||||
FfiResult::FfiUnsafe(s) => {
|
||||
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
|
||||
}
|
||||
FfiResult::FfiBadStruct(_, s) => {
|
||||
// FIXME: This diagnostic is difficult to read, and doesn't
|
||||
// point at the relevant field.
|
||||
self.cx.span_lint(IMPROPER_CTYPES,
|
||||
sp,
|
||||
&format!("found non-foreign-function-safe member in struct \
|
||||
marked #[repr(C)]: {}",
|
||||
s));
|
||||
}
|
||||
FfiResult::FfiBadUnion(_, s) => {
|
||||
// FIXME: This diagnostic is difficult to read, and doesn't
|
||||
// point at the relevant field.
|
||||
self.cx.span_lint(IMPROPER_CTYPES,
|
||||
sp,
|
||||
&format!("found non-foreign-function-safe member in union \
|
||||
marked #[repr(C)]: {}",
|
||||
s));
|
||||
}
|
||||
FfiResult::FfiBadEnum(_, s) => {
|
||||
// FIXME: This diagnostic is difficult to read, and doesn't
|
||||
// point at the relevant variant.
|
||||
self.cx.span_lint(IMPROPER_CTYPES,
|
||||
sp,
|
||||
&format!("found non-foreign-function-safe member in enum: {}",
|
||||
s));
|
||||
FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => {
|
||||
let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}",
|
||||
unsafe_ty, reason);
|
||||
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
|
||||
if let Some(s) = help {
|
||||
diag.help(s);
|
||||
}
|
||||
if let ty::TyAdt(def, _) = unsafe_ty.sty {
|
||||
if let Some(sp) = self.cx.tcx.hir.span_if_local(def.did) {
|
||||
diag.span_note(sp, "type defined here");
|
||||
}
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use std::rc::Rc;
|
||||
use rustc_data_structures::bitvec::BitMatrix;
|
||||
use rustc_data_structures::bitvec::SparseBitMatrix;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
@ -69,9 +69,7 @@ impl RegionValueElements {
|
||||
|
||||
/// Iterates over the `RegionElementIndex` for all points in the CFG.
|
||||
pub(super) fn all_point_indices<'a>(&'a self) -> impl Iterator<Item = RegionElementIndex> + 'a {
|
||||
(0..self.num_points).map(move |i| {
|
||||
RegionElementIndex::new(i + self.num_universal_regions)
|
||||
})
|
||||
(0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions))
|
||||
}
|
||||
|
||||
/// Iterates over the `RegionElementIndex` for all points in the CFG.
|
||||
@ -132,7 +130,7 @@ impl RegionValueElements {
|
||||
}
|
||||
|
||||
/// A newtype for the integers that represent one of the possible
|
||||
/// elements in a region. These are the rows in the `BitMatrix` that
|
||||
/// elements in a region. These are the rows in the `SparseBitMatrix` that
|
||||
/// is used to store the values of all regions. They have the following
|
||||
/// convention:
|
||||
///
|
||||
@ -154,7 +152,6 @@ pub(super) enum RegionElement {
|
||||
UniversalRegion(RegionVid),
|
||||
}
|
||||
|
||||
|
||||
pub(super) trait ToElementIndex {
|
||||
fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex;
|
||||
}
|
||||
@ -184,18 +181,18 @@ impl ToElementIndex for RegionElementIndex {
|
||||
}
|
||||
|
||||
/// Stores the values for a set of regions. These are stored in a
|
||||
/// compact `BitMatrix` representation, with one row per region
|
||||
/// compact `SparseBitMatrix` representation, with one row per region
|
||||
/// variable. The columns consist of either universal regions or
|
||||
/// points in the CFG.
|
||||
#[derive(Clone)]
|
||||
pub(super) struct RegionValues {
|
||||
elements: Rc<RegionValueElements>,
|
||||
matrix: BitMatrix,
|
||||
matrix: SparseBitMatrix<RegionVid, RegionElementIndex>,
|
||||
|
||||
/// If cause tracking is enabled, maps from a pair (r, e)
|
||||
/// consisting of a region `r` that contains some element `e` to
|
||||
/// the reason that the element is contained. There should be an
|
||||
/// entry for every bit set to 1 in `BitMatrix`.
|
||||
/// entry for every bit set to 1 in `SparseBitMatrix`.
|
||||
causes: Option<CauseMap>,
|
||||
}
|
||||
|
||||
@ -214,7 +211,10 @@ impl RegionValues {
|
||||
|
||||
Self {
|
||||
elements: elements.clone(),
|
||||
matrix: BitMatrix::new(num_region_variables, elements.num_elements()),
|
||||
matrix: SparseBitMatrix::new(
|
||||
RegionVid::new(num_region_variables),
|
||||
RegionElementIndex::new(elements.num_elements()),
|
||||
),
|
||||
causes: if track_causes.0 {
|
||||
Some(CauseMap::default())
|
||||
} else {
|
||||
@ -238,7 +238,7 @@ impl RegionValues {
|
||||
where
|
||||
F: FnOnce(&CauseMap) -> Cause,
|
||||
{
|
||||
if self.matrix.add(r.index(), i.index()) {
|
||||
if self.matrix.add(r, i) {
|
||||
debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i));
|
||||
|
||||
if let Some(causes) = &mut self.causes {
|
||||
@ -289,13 +289,12 @@ impl RegionValues {
|
||||
constraint_location: Location,
|
||||
constraint_span: Span,
|
||||
) -> bool {
|
||||
// We could optimize this by improving `BitMatrix::merge` so
|
||||
// We could optimize this by improving `SparseBitMatrix::merge` so
|
||||
// it does not always merge an entire row. That would
|
||||
// complicate causal tracking though.
|
||||
debug!(
|
||||
"add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
|
||||
from_region,
|
||||
to_region
|
||||
from_region, to_region
|
||||
);
|
||||
let mut changed = false;
|
||||
for elem in self.elements.all_universal_region_indices() {
|
||||
@ -315,7 +314,7 @@ impl RegionValues {
|
||||
/// True if the region `r` contains the given element.
|
||||
pub(super) fn contains<E: ToElementIndex>(&self, r: RegionVid, elem: E) -> bool {
|
||||
let i = self.elements.index(elem);
|
||||
self.matrix.contains(r.index(), i.index())
|
||||
self.matrix.contains(r, i)
|
||||
}
|
||||
|
||||
/// Iterate over the value of the region `r`, yielding up element
|
||||
@ -325,9 +324,7 @@ impl RegionValues {
|
||||
&'a self,
|
||||
r: RegionVid,
|
||||
) -> impl Iterator<Item = RegionElementIndex> + 'a {
|
||||
self.matrix
|
||||
.iter(r.index())
|
||||
.map(move |i| RegionElementIndex::new(i))
|
||||
self.matrix.iter(r).map(move |i| i)
|
||||
}
|
||||
|
||||
/// Returns just the universal regions that are contained in a given region's value.
|
||||
@ -415,9 +412,7 @@ impl RegionValues {
|
||||
assert_eq!(location1.block, location2.block);
|
||||
str.push_str(&format!(
|
||||
"{:?}[{}..={}]",
|
||||
location1.block,
|
||||
location1.statement_index,
|
||||
location2.statement_index
|
||||
location1.block, location1.statement_index, location2.statement_index
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -122,8 +122,9 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut symbol_white_list = cgcx.exported_symbols[&LOCAL_CRATE]
|
||||
let exported_symbols = cgcx.exported_symbols
|
||||
.as_ref().expect("needs exported symbols for LTO");
|
||||
let mut symbol_white_list = exported_symbols[&LOCAL_CRATE]
|
||||
.iter()
|
||||
.filter_map(symbol_filter)
|
||||
.collect::<Vec<CString>>();
|
||||
@ -156,8 +157,10 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
||||
}
|
||||
|
||||
for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
|
||||
let exported_symbols = cgcx.exported_symbols
|
||||
.as_ref().expect("needs exported symbols for LTO");
|
||||
symbol_white_list.extend(
|
||||
cgcx.exported_symbols[&cnum]
|
||||
exported_symbols[&cnum]
|
||||
.iter()
|
||||
.filter_map(symbol_filter));
|
||||
|
||||
|
@ -333,7 +333,7 @@ pub struct CodegenContext {
|
||||
pub no_landing_pads: bool,
|
||||
pub save_temps: bool,
|
||||
pub fewer_names: bool,
|
||||
pub exported_symbols: Arc<ExportedSymbols>,
|
||||
pub exported_symbols: Option<Arc<ExportedSymbols>>,
|
||||
pub opts: Arc<config::Options>,
|
||||
pub crate_types: Vec<config::CrateType>,
|
||||
pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>,
|
||||
@ -1394,14 +1394,25 @@ fn start_executing_work(tcx: TyCtxt,
|
||||
allocator_config: Arc<ModuleConfig>)
|
||||
-> thread::JoinHandle<Result<CompiledModules, ()>> {
|
||||
let coordinator_send = tcx.tx_to_llvm_workers.clone();
|
||||
let mut exported_symbols = FxHashMap();
|
||||
exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
|
||||
for &cnum in tcx.crates().iter() {
|
||||
exported_symbols.insert(cnum, tcx.exported_symbols(cnum));
|
||||
}
|
||||
let exported_symbols = Arc::new(exported_symbols);
|
||||
let sess = tcx.sess;
|
||||
|
||||
let exported_symbols = match sess.lto() {
|
||||
Lto::No => None,
|
||||
Lto::ThinLocal => {
|
||||
let mut exported_symbols = FxHashMap();
|
||||
exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
|
||||
Some(Arc::new(exported_symbols))
|
||||
}
|
||||
Lto::Yes | Lto::Fat | Lto::Thin => {
|
||||
let mut exported_symbols = FxHashMap();
|
||||
exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
|
||||
for &cnum in tcx.crates().iter() {
|
||||
exported_symbols.insert(cnum, tcx.exported_symbols(cnum));
|
||||
}
|
||||
Some(Arc::new(exported_symbols))
|
||||
}
|
||||
};
|
||||
|
||||
// First up, convert our jobserver into a helper thread so we can use normal
|
||||
// mpsc channels to manage our messages and such.
|
||||
// After we've requested tokens then we'll, when we can,
|
||||
|
@ -17,14 +17,24 @@ use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::{InferOk, InferResult};
|
||||
use rustc::infer::LateBoundRegionConversionTime;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::traits::error_reporting::ArgKind;
|
||||
use rustc::ty::{self, ToPolyTraitRef, Ty};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::TypeFoldable;
|
||||
use std::cmp;
|
||||
use std::iter;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::codemap::Span;
|
||||
use rustc::hir;
|
||||
|
||||
/// What signature do we *expect* the closure to have from context?
|
||||
#[derive(Debug)]
|
||||
struct ExpectedSig<'tcx> {
|
||||
/// Span that gave us this expectation, if we know that.
|
||||
cause_span: Option<Span>,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
}
|
||||
|
||||
struct ClosureSignatures<'tcx> {
|
||||
bound_sig: ty::PolyFnSig<'tcx>,
|
||||
liberated_sig: ty::FnSig<'tcx>,
|
||||
@ -42,8 +52,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
) -> Ty<'tcx> {
|
||||
debug!(
|
||||
"check_expr_closure(expr={:?},expected={:?})",
|
||||
expr,
|
||||
expected
|
||||
expr, expected
|
||||
);
|
||||
|
||||
// It's always helpful for inference if we know the kind of
|
||||
@ -64,12 +73,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
decl: &'gcx hir::FnDecl,
|
||||
body: &'gcx hir::Body,
|
||||
gen: Option<hir::GeneratorMovability>,
|
||||
expected_sig: Option<ty::FnSig<'tcx>>,
|
||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
debug!(
|
||||
"check_closure(opt_kind={:?}, expected_sig={:?})",
|
||||
opt_kind,
|
||||
expected_sig
|
||||
opt_kind, expected_sig
|
||||
);
|
||||
|
||||
let expr_def_id = self.tcx.hir.local_def_id(expr.id);
|
||||
@ -109,19 +117,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let closure_type = self.tcx.mk_closure(expr_def_id, substs);
|
||||
|
||||
if let Some(GeneratorTypes { yield_ty, interior }) = generator_types {
|
||||
self.demand_eqtype(expr.span,
|
||||
yield_ty,
|
||||
substs.generator_yield_ty(expr_def_id, self.tcx));
|
||||
self.demand_eqtype(expr.span,
|
||||
liberated_sig.output(),
|
||||
substs.generator_return_ty(expr_def_id, self.tcx));
|
||||
self.demand_eqtype(
|
||||
expr.span,
|
||||
yield_ty,
|
||||
substs.generator_yield_ty(expr_def_id, self.tcx),
|
||||
);
|
||||
self.demand_eqtype(
|
||||
expr.span,
|
||||
liberated_sig.output(),
|
||||
substs.generator_return_ty(expr_def_id, self.tcx),
|
||||
);
|
||||
return self.tcx.mk_generator(expr_def_id, substs, interior);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"check_closure: expr.id={:?} closure_type={:?}",
|
||||
expr.id,
|
||||
closure_type
|
||||
expr.id, closure_type
|
||||
);
|
||||
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
@ -138,29 +149,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
debug!(
|
||||
"check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}",
|
||||
expr_def_id,
|
||||
sig,
|
||||
opt_kind
|
||||
expr_def_id, sig, opt_kind
|
||||
);
|
||||
|
||||
let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
|
||||
self.demand_eqtype(expr.span,
|
||||
sig_fn_ptr_ty,
|
||||
substs.closure_sig_ty(expr_def_id, self.tcx));
|
||||
self.demand_eqtype(
|
||||
expr.span,
|
||||
sig_fn_ptr_ty,
|
||||
substs.closure_sig_ty(expr_def_id, self.tcx),
|
||||
);
|
||||
|
||||
if let Some(kind) = opt_kind {
|
||||
self.demand_eqtype(expr.span,
|
||||
kind.to_ty(self.tcx),
|
||||
substs.closure_kind_ty(expr_def_id, self.tcx));
|
||||
self.demand_eqtype(
|
||||
expr.span,
|
||||
kind.to_ty(self.tcx),
|
||||
substs.closure_kind_ty(expr_def_id, self.tcx),
|
||||
);
|
||||
}
|
||||
|
||||
closure_type
|
||||
}
|
||||
|
||||
/// Given the expected type, figures out what it can about this closure we
|
||||
/// are about to type check:
|
||||
fn deduce_expectations_from_expected_type(
|
||||
&self,
|
||||
expected_ty: Ty<'tcx>,
|
||||
) -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
debug!(
|
||||
"deduce_expectations_from_expected_type(expected_ty={:?})",
|
||||
expected_ty
|
||||
@ -172,7 +187,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
.projection_bounds()
|
||||
.filter_map(|pb| {
|
||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
|
||||
self.deduce_sig_from_projection(&pb)
|
||||
self.deduce_sig_from_projection(None, &pb)
|
||||
})
|
||||
.next();
|
||||
let kind = object_type
|
||||
@ -181,7 +196,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
(sig, kind)
|
||||
}
|
||||
ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
|
||||
ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)),
|
||||
ty::TyFnPtr(sig) => {
|
||||
let expected_sig = ExpectedSig {
|
||||
cause_span: None,
|
||||
sig: sig.skip_binder().clone(),
|
||||
};
|
||||
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
||||
}
|
||||
_ => (None, None),
|
||||
}
|
||||
}
|
||||
@ -189,7 +210,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn deduce_expectations_from_obligations(
|
||||
&self,
|
||||
expected_vid: ty::TyVid,
|
||||
) -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
let fulfillment_cx = self.fulfillment_cx.borrow();
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
|
||||
@ -209,7 +230,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::Projection(ref proj_predicate) => {
|
||||
let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx);
|
||||
self.self_type_matches_expected_vid(trait_ref, expected_vid)
|
||||
.and_then(|_| self.deduce_sig_from_projection(proj_predicate))
|
||||
.and_then(|_| {
|
||||
self.deduce_sig_from_projection(
|
||||
Some(obligation.cause.span),
|
||||
proj_predicate,
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
@ -259,10 +285,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
|
||||
/// everything we need to know about a closure.
|
||||
///
|
||||
/// The `cause_span` should be the span that caused us to
|
||||
/// have this expected signature, or `None` if we can't readily
|
||||
/// know that.
|
||||
fn deduce_sig_from_projection(
|
||||
&self,
|
||||
cause_span: Option<Span>,
|
||||
projection: &ty::PolyProjectionPredicate<'tcx>,
|
||||
) -> Option<ty::FnSig<'tcx>> {
|
||||
) -> Option<ExpectedSig<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
debug!("deduce_sig_from_projection({:?})", projection);
|
||||
@ -294,16 +325,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ret_param_ty
|
||||
);
|
||||
|
||||
let fn_sig = self.tcx.mk_fn_sig(
|
||||
let sig = self.tcx.mk_fn_sig(
|
||||
input_tys.cloned(),
|
||||
ret_param_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
);
|
||||
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
|
||||
debug!("deduce_sig_from_projection: sig {:?}", sig);
|
||||
|
||||
Some(fn_sig)
|
||||
Some(ExpectedSig { cause_span, sig })
|
||||
}
|
||||
|
||||
fn self_type_matches_expected_vid(
|
||||
@ -314,8 +345,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let self_ty = self.shallow_resolve(trait_ref.self_ty());
|
||||
debug!(
|
||||
"self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
|
||||
trait_ref,
|
||||
self_ty
|
||||
trait_ref, self_ty
|
||||
);
|
||||
match self_ty.sty {
|
||||
ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
|
||||
@ -328,7 +358,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
expr_def_id: DefId,
|
||||
decl: &hir::FnDecl,
|
||||
body: &hir::Body,
|
||||
expected_sig: Option<ty::FnSig<'tcx>>,
|
||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
if let Some(e) = expected_sig {
|
||||
self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
|
||||
@ -404,7 +434,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
expr_def_id: DefId,
|
||||
decl: &hir::FnDecl,
|
||||
body: &hir::Body,
|
||||
expected_sig: ty::FnSig<'tcx>,
|
||||
expected_sig: ExpectedSig<'tcx>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
debug!(
|
||||
"sig_of_closure_with_expectation(expected_sig={:?})",
|
||||
@ -414,20 +444,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// Watch out for some surprises and just ignore the
|
||||
// expectation if things don't see to match up with what we
|
||||
// expect.
|
||||
if expected_sig.variadic != decl.variadic {
|
||||
return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
|
||||
} else if expected_sig.inputs_and_output.len() != decl.inputs.len() + 1 {
|
||||
// we could probably handle this case more gracefully
|
||||
if expected_sig.sig.variadic != decl.variadic {
|
||||
return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
|
||||
} else if expected_sig.sig.inputs_and_output.len() != decl.inputs.len() + 1 {
|
||||
return self.sig_of_closure_with_mismatched_number_of_arguments(
|
||||
expr_def_id,
|
||||
decl,
|
||||
body,
|
||||
expected_sig,
|
||||
);
|
||||
}
|
||||
|
||||
// Create a `PolyFnSig`. Note the oddity that late bound
|
||||
// regions appearing free in `expected_sig` are now bound up
|
||||
// in this binder we are creating.
|
||||
assert!(!expected_sig.has_regions_escaping_depth(1));
|
||||
assert!(!expected_sig.sig.has_regions_escaping_depth(1));
|
||||
let bound_sig = ty::Binder(self.tcx.mk_fn_sig(
|
||||
expected_sig.inputs().iter().cloned(),
|
||||
expected_sig.output(),
|
||||
expected_sig.sig.inputs().iter().cloned(),
|
||||
expected_sig.sig.output(),
|
||||
decl.variadic,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::RustCall,
|
||||
@ -453,6 +487,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
closure_sigs
|
||||
}
|
||||
|
||||
fn sig_of_closure_with_mismatched_number_of_arguments(
|
||||
&self,
|
||||
expr_def_id: DefId,
|
||||
decl: &hir::FnDecl,
|
||||
body: &hir::Body,
|
||||
expected_sig: ExpectedSig<'tcx>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
let expr_map_node = self.tcx.hir.get_if_local(expr_def_id).unwrap();
|
||||
let expected_args: Vec<_> = expected_sig
|
||||
.sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.map(|ty| ArgKind::from_expected_ty(ty))
|
||||
.collect();
|
||||
let (closure_span, found_args) = self.get_fn_like_arguments(expr_map_node);
|
||||
let expected_span = expected_sig.cause_span.unwrap_or(closure_span);
|
||||
self.report_arg_count_mismatch(
|
||||
expected_span,
|
||||
Some(closure_span),
|
||||
expected_args,
|
||||
found_args,
|
||||
true,
|
||||
).emit();
|
||||
|
||||
let error_sig = self.error_sig_of_closure(decl);
|
||||
|
||||
self.closure_sigs(expr_def_id, body, error_sig)
|
||||
}
|
||||
|
||||
/// Enforce the user's types against the expectation. See
|
||||
/// `sig_of_closure_with_expectation` for details on the overall
|
||||
/// strategy.
|
||||
@ -558,13 +621,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
/// Converts the types that the user supplied, in case that doing
|
||||
/// so should yield an error, but returns back a signature where
|
||||
/// all parameters are of type `TyErr`.
|
||||
fn error_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> {
|
||||
let astconv: &AstConv = self;
|
||||
|
||||
let supplied_arguments = decl.inputs.iter().map(|a| {
|
||||
// Convert the types that the user supplied (if any), but ignore them.
|
||||
astconv.ast_ty_to_ty(a);
|
||||
self.tcx.types.err
|
||||
});
|
||||
|
||||
match decl.output {
|
||||
hir::Return(ref output) => {
|
||||
astconv.ast_ty_to_ty(&output);
|
||||
}
|
||||
hir::DefaultReturn(_) => {}
|
||||
}
|
||||
|
||||
let result = ty::Binder(self.tcx.mk_fn_sig(
|
||||
supplied_arguments,
|
||||
self.tcx.types.err,
|
||||
decl.variadic,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::RustCall,
|
||||
));
|
||||
|
||||
debug!("supplied_sig_of_closure: result={:?}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn closure_sigs(
|
||||
&self,
|
||||
expr_def_id: DefId,
|
||||
body: &hir::Body,
|
||||
bound_sig: ty::PolyFnSig<'tcx>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, &bound_sig);
|
||||
let liberated_sig = self.tcx()
|
||||
.liberate_late_bound_regions(expr_def_id, &bound_sig);
|
||||
let liberated_sig = self.inh.normalize_associated_types_in(
|
||||
body.value.span,
|
||||
body.value.id,
|
||||
|
@ -186,7 +186,7 @@ declare_features! (
|
||||
(active, rustc_attrs, "1.0.0", Some(29642)),
|
||||
|
||||
// Allows the use of non lexical lifetimes; RFC 2094
|
||||
(active, nll, "1.0.0", Some(44928)),
|
||||
(active, nll, "1.0.0", Some(43234)),
|
||||
|
||||
// Allows the use of #[allow_internal_unstable]. This is an
|
||||
// attribute on macro_rules! and can't use the attribute handling
|
||||
|
@ -2630,8 +2630,7 @@ impl<'a> Parser<'a> {
|
||||
// A tuple index may not have a suffix
|
||||
self.expect_no_suffix(sp, "tuple index", suf);
|
||||
|
||||
let dot_span = self.prev_span;
|
||||
hi = self.span;
|
||||
let idx_span = self.span;
|
||||
self.bump();
|
||||
|
||||
let invalid_msg = "invalid tuple or struct index";
|
||||
@ -2646,9 +2645,8 @@ impl<'a> Parser<'a> {
|
||||
n.to_string());
|
||||
err.emit();
|
||||
}
|
||||
let id = respan(dot_span.to(hi), n);
|
||||
let field = self.mk_tup_field(e, id);
|
||||
e = self.mk_expr(lo.to(hi), field, ThinVec::new());
|
||||
let field = self.mk_tup_field(e, respan(idx_span, n));
|
||||
e = self.mk_expr(lo.to(idx_span), field, ThinVec::new());
|
||||
}
|
||||
None => {
|
||||
let prev_span = self.prev_span;
|
||||
|
@ -37,13 +37,13 @@ struct D {
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn foo(x: A); //~ ERROR found struct without foreign-function-safe
|
||||
fn bar(x: B); //~ ERROR foreign-function-safe
|
||||
fn foo(x: A); //~ ERROR type `A` which is not FFI-safe
|
||||
fn bar(x: B); //~ ERROR type `A`
|
||||
fn baz(x: C);
|
||||
fn qux(x: A2); //~ ERROR foreign-function-safe
|
||||
fn quux(x: B2); //~ ERROR foreign-function-safe
|
||||
fn qux(x: A2); //~ ERROR type `A`
|
||||
fn quux(x: B2); //~ ERROR type `A`
|
||||
fn corge(x: C2);
|
||||
fn fred(x: D); //~ ERROR foreign-function-safe
|
||||
fn fred(x: D); //~ ERROR type `A`
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -13,7 +13,7 @@
|
||||
pub struct Foo;
|
||||
|
||||
extern {
|
||||
pub fn foo(x: (Foo)); //~ ERROR found struct without
|
||||
pub fn foo(x: (Foo)); //~ ERROR unspecified layout
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -16,11 +16,23 @@ enum U { A }
|
||||
enum B { C, D }
|
||||
enum T { E, F, G }
|
||||
|
||||
#[repr(C)]
|
||||
enum ReprC { A, B, C }
|
||||
|
||||
#[repr(u8)]
|
||||
enum U8 { A, B, C }
|
||||
|
||||
#[repr(isize)]
|
||||
enum Isize { A, B, C }
|
||||
|
||||
extern {
|
||||
fn zf(x: Z);
|
||||
fn uf(x: U); //~ ERROR found enum without foreign-function-safe
|
||||
fn bf(x: B); //~ ERROR found enum without foreign-function-safe
|
||||
fn tf(x: T); //~ ERROR found enum without foreign-function-safe
|
||||
fn uf(x: U); //~ ERROR enum has no representation hint
|
||||
fn bf(x: B); //~ ERROR enum has no representation hint
|
||||
fn tf(x: T); //~ ERROR enum has no representation hint
|
||||
fn reprc(x: ReprC);
|
||||
fn u8(x: U8);
|
||||
fn isize(x: Isize);
|
||||
}
|
||||
|
||||
pub fn main() { }
|
||||
|
@ -22,7 +22,7 @@ union W {
|
||||
|
||||
extern "C" {
|
||||
static FOREIGN1: U; // OK
|
||||
static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation
|
||||
static FOREIGN2: W; //~ ERROR union has unspecified layout
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
30
src/test/run-pass/hygiene/issue-47312.rs
Normal file
30
src/test/run-pass/hygiene/issue-47312.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty pretty-printing is unhygienic
|
||||
|
||||
#![feature(decl_macro)]
|
||||
#![allow(unused)]
|
||||
|
||||
mod foo {
|
||||
pub macro m($s:tt, $i:tt) {
|
||||
$s.$i
|
||||
}
|
||||
}
|
||||
|
||||
mod bar {
|
||||
struct S(i32);
|
||||
fn f() {
|
||||
let s = S(0);
|
||||
::foo::m!(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -50,6 +50,14 @@ fn closure_hr_elided_return() -> impl Fn(&u32) -> &u32 { |x| x }
|
||||
fn closure_pass_through_elided_return(x: impl Fn(&u32) -> &u32) -> impl Fn(&u32) -> &u32 { x }
|
||||
fn closure_pass_through_reference_elided(x: &impl Fn(&u32) -> &u32) -> &impl Fn(&u32) -> &u32 { x }
|
||||
|
||||
fn nested_lifetime<'a>(input: &'a str)
|
||||
-> impl Iterator<Item = impl Iterator<Item = i32> + 'a> + 'a
|
||||
{
|
||||
input.lines().map(|line| {
|
||||
line.split_whitespace().map(|cell| cell.parse().unwrap())
|
||||
})
|
||||
}
|
||||
|
||||
fn pass_through_elision(x: &u32) -> impl Into<&u32> { x }
|
||||
fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) -> &u32> { x }
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-panic.rs
|
||||
// compile-flags:--error-format human
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_panic;
|
||||
|
@ -1,7 +1,7 @@
|
||||
error: proc-macro derive panicked
|
||||
--> $DIR/load-panic.rs:16:10
|
||||
--> $DIR/load-panic.rs:17:10
|
||||
|
|
||||
16 | #[derive(A)]
|
||||
17 | #[derive(A)]
|
||||
| ^
|
||||
|
|
||||
= help: message: nope!
|
||||
|
@ -51,27 +51,27 @@ pub struct TransparentCustomZst(i32, ZeroSize);
|
||||
pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
|
||||
|
||||
extern {
|
||||
pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without
|
||||
pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without
|
||||
pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type
|
||||
pub fn str_type(p: &str); //~ ERROR: found Rust type
|
||||
pub fn box_type(p: Box<u32>); //~ ERROR found struct without
|
||||
pub fn char_type(p: char); //~ ERROR found Rust type
|
||||
pub fn i128_type(p: i128); //~ ERROR found Rust type
|
||||
pub fn u128_type(p: u128); //~ ERROR found Rust type
|
||||
pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type
|
||||
pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
|
||||
pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
|
||||
pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
|
||||
pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type
|
||||
pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo`
|
||||
pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
|
||||
pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
|
||||
pub fn str_type(p: &str); //~ ERROR: uses type `str`
|
||||
pub fn box_type(p: Box<u32>); //~ ERROR uses type `std::boxed::Box<u32>`
|
||||
pub fn char_type(p: char); //~ ERROR uses type `char`
|
||||
pub fn i128_type(p: i128); //~ ERROR uses type `i128`
|
||||
pub fn u128_type(p: u128); //~ ERROR uses type `u128`
|
||||
pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone`
|
||||
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
|
||||
pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
|
||||
pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields
|
||||
pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData
|
||||
pub fn zero_size_phantom_toplevel()
|
||||
-> ::std::marker::PhantomData<bool>; //~ ERROR: found zero-sized type
|
||||
pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
|
||||
pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
|
||||
pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without
|
||||
pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128`
|
||||
pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str`
|
||||
pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without
|
||||
-> ::std::marker::PhantomData<bool>; //~ ERROR: composed only of PhantomData
|
||||
pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific
|
||||
pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific
|
||||
pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box<u32>`
|
||||
pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
|
||||
pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
|
||||
pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box<u32>`
|
||||
|
||||
pub fn good3(fptr: Option<extern fn()>);
|
||||
pub fn good4(aptr: &[u8; 4 as usize]);
|
170
src/test/ui/lint-ctypes.stderr
Normal file
170
src/test/ui/lint-ctypes.stderr
Normal file
@ -0,0 +1,170 @@
|
||||
error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:54:28
|
||||
|
|
||||
54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo`
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-ctypes.rs:11:9
|
||||
|
|
||||
11 | #![deny(improper_ctypes)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
|
||||
note: type defined here
|
||||
--> $DIR/lint-ctypes.rs:32:1
|
||||
|
|
||||
32 | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:55:28
|
||||
|
|
||||
55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
|
||||
note: type defined here
|
||||
--> $DIR/lint-ctypes.rs:32:1
|
||||
|
|
||||
32 | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent
|
||||
--> $DIR/lint-ctypes.rs:56:26
|
||||
|
|
||||
56 | pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: consider using a raw pointer instead
|
||||
|
||||
error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent
|
||||
--> $DIR/lint-ctypes.rs:57:24
|
||||
|
|
||||
57 | pub fn str_type(p: &str); //~ ERROR: uses type `str`
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider using `*const u8` and a length instead
|
||||
|
||||
error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:58:24
|
||||
|
|
||||
58 | pub fn box_type(p: Box<u32>); //~ ERROR uses type `std::boxed::Box<u32>`
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
|
||||
|
||||
error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent
|
||||
--> $DIR/lint-ctypes.rs:59:25
|
||||
|
|
||||
59 | pub fn char_type(p: char); //~ ERROR uses type `char`
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider using `u32` or `libc::wchar_t` instead
|
||||
|
||||
error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
|
||||
--> $DIR/lint-ctypes.rs:60:25
|
||||
|
|
||||
60 | pub fn i128_type(p: i128); //~ ERROR uses type `i128`
|
||||
| ^^^^
|
||||
|
||||
error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
|
||||
--> $DIR/lint-ctypes.rs:61:25
|
||||
|
|
||||
61 | pub fn u128_type(p: u128); //~ ERROR uses type `u128`
|
||||
| ^^^^
|
||||
|
||||
error: `extern` block uses type `std::clone::Clone` which is not FFI-safe: trait objects have no C equivalent
|
||||
--> $DIR/lint-ctypes.rs:62:26
|
||||
|
|
||||
62 | pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone`
|
||||
| ^^^^^^
|
||||
|
||||
error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:63:26
|
||||
|
|
||||
63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider using a struct instead
|
||||
|
||||
error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:64:27
|
||||
|
|
||||
64 | pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: consider using a struct instead
|
||||
|
||||
error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct has no fields
|
||||
--> $DIR/lint-ctypes.rs:65:25
|
||||
|
|
||||
65 | pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= help: consider adding a member to this struct
|
||||
note: type defined here
|
||||
--> $DIR/lint-ctypes.rs:28:1
|
||||
|
|
||||
28 | pub struct ZeroSize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData
|
||||
--> $DIR/lint-ctypes.rs:66:33
|
||||
|
|
||||
66 | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `std::marker::PhantomData<bool>` which is not FFI-safe: composed only of PhantomData
|
||||
--> $DIR/lint-ctypes.rs:68:12
|
||||
|
|
||||
68 | -> ::std::marker::PhantomData<bool>; //~ ERROR: composed only of PhantomData
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention
|
||||
--> $DIR/lint-ctypes.rs:69:23
|
||||
|
|
||||
69 | pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: consider using an `fn "extern"(...) -> ...` function pointer instead
|
||||
|
||||
error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention
|
||||
--> $DIR/lint-ctypes.rs:70:24
|
||||
|
|
||||
70 | pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider using an `fn "extern"(...) -> ...` function pointer instead
|
||||
|
||||
error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:71:28
|
||||
|
|
||||
71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box<u32>`
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
|
||||
|
||||
error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
|
||||
--> $DIR/lint-ctypes.rs:72:32
|
||||
|
|
||||
72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent
|
||||
--> $DIR/lint-ctypes.rs:73:31
|
||||
|
|
||||
73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using `*const u8` and a length instead
|
||||
|
||||
error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
|
||||
--> $DIR/lint-ctypes.rs:74:30
|
||||
|
|
||||
74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box<u32>`
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for #47244: in this specific scenario, when the
|
||||
// expected type indicated 1 argument but the closure takes two, we
|
||||
// would (early on) create type variables for the type of `b`. If the
|
||||
// user then attempts to invoke a method on `b`, we would get an error
|
||||
// saying that the type of `b` must be known, which was not very
|
||||
// helpful.
|
||||
|
||||
use std::collections::HashMap;
|
||||
fn main() {
|
||||
|
||||
let m = HashMap::new();
|
||||
m.insert( "foo", "bar" );
|
||||
|
||||
m.iter().map( |_, b| {
|
||||
//~^ ERROR closure is expected to take a single 2-tuple
|
||||
|
||||
b.to_string()
|
||||
});
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
|
||||
--> $DIR/closure-arg-count-expected-type-issue-47244.rs:24:14
|
||||
|
|
||||
24 | m.iter().map( |_, b| {
|
||||
| ^^^ ------ takes 2 distinct arguments
|
||||
| |
|
||||
| expected closure that takes a single 2-tuple as argument
|
||||
help: change the closure to accept a tuple instead of individual arguments
|
||||
|
|
||||
24 | m.iter().map( |(_, b)| {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit ce47e529d29f0bf19b31ae80b37b467e42fb97e2
|
||||
Subproject commit d5e233a720495c52af25d8f6dcc9e55e1193beb9
|
Loading…
Reference in New Issue
Block a user