Auto merge of #60296 - Centril:rollup-qh9la7k, r=Centril
Rollup of 12 pull requests Successful merges: - #59734 (Prevent failure in case no space left on device in rustdoc) - #59940 (Set cfg(test) when rustdoc is running with --test option) - #60134 (Fix index-page generation) - #60165 (Add Pin::{into_inner,into_inner_unchecked}) - #60183 (Chalkify: Add builtin Copy/Clone) - #60225 (Introduce hir::ExprKind::Use and employ in for loop desugaring.) - #60247 (Implement Debug for Place using Place::iterate) - #60259 (Derive Default instead of new in applicable lint) - #60267 (Add feature-gate for f16c target feature) - #60284 (Do not allow const generics to depend on type parameters) - #60285 (Do not ICE when checking types against foreign fn) - #60289 (Make `-Z allow-features` work for stdlib features) Failed merges: r? @ghost
This commit is contained in:
commit
180edc21ee
@ -1523,7 +1523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "minifier"
|
||||
version = "0.0.29"
|
||||
version = "0.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3038,7 +3038,7 @@ dependencies = [
|
||||
name = "rustdoc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -4170,7 +4170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
||||
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4950cb2617b1933e2da0446e864dfe0d6a22c22ff72297996c46e6a63b210b"
|
||||
"checksum minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "4c909e78edf61f3aa0dd2086da168cdf304329044bbf248768ca3d20253ec8c0"
|
||||
"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
|
||||
"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c"
|
||||
"checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e"
|
||||
|
@ -349,6 +349,18 @@ where
|
||||
// around pinning.
|
||||
unsafe { Pin::new_unchecked(pointer) }
|
||||
}
|
||||
|
||||
/// Unwraps this `Pin<P>` returning the underlying pointer.
|
||||
///
|
||||
/// This requires that the data inside this `Pin` is [`Unpin`] so that we
|
||||
/// can ignore the pinning invariants when unwrapping it.
|
||||
///
|
||||
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
|
||||
#[unstable(feature = "pin_into_inner", issue = "60245")]
|
||||
#[inline(always)]
|
||||
pub fn into_inner(pin: Pin<P>) -> P {
|
||||
pin.pointer
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Deref> Pin<P> {
|
||||
@ -434,6 +446,28 @@ impl<P: Deref> Pin<P> {
|
||||
pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> {
|
||||
unsafe { Pin::new_unchecked(&*self.pointer) }
|
||||
}
|
||||
|
||||
/// Unwraps this `Pin<P>` returning the underlying pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe. You must guarantee that you will continue to
|
||||
/// treat the pointer `P` as pinned after you call this function, so that
|
||||
/// the invariants on the `Pin` type can be upheld. If the code using the
|
||||
/// resulting `P` does not continue to maintain the pinning invariants that
|
||||
/// is a violation of the API contract and may lead to undefined behavior in
|
||||
/// later (safe) operations.
|
||||
///
|
||||
/// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
|
||||
/// instead.
|
||||
///
|
||||
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
|
||||
/// [`Pin::into_inner`]: #method.into_inner
|
||||
#[unstable(feature = "pin_into_inner", issue = "60245")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn into_inner_unchecked(pin: Pin<P>) -> P {
|
||||
pin.pointer
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: DerefMut> Pin<P> {
|
||||
|
@ -369,6 +369,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
hir::ExprKind::AddrOf(_, ref e) |
|
||||
hir::ExprKind::Cast(ref e, _) |
|
||||
hir::ExprKind::Type(ref e, _) |
|
||||
hir::ExprKind::Use(ref e) |
|
||||
hir::ExprKind::Unary(_, ref e) |
|
||||
hir::ExprKind::Field(ref e, _) |
|
||||
hir::ExprKind::Yield(ref e) |
|
||||
|
@ -1029,6 +1029,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
visitor.visit_expr(subexpression);
|
||||
visitor.visit_ty(typ)
|
||||
}
|
||||
ExprKind::Use(ref subexpression) => {
|
||||
visitor.visit_expr(subexpression);
|
||||
}
|
||||
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
|
||||
visitor.visit_expr(head_expression);
|
||||
visitor.visit_expr(if_block);
|
||||
|
@ -4738,16 +4738,11 @@ impl<'a> LoweringContext<'a> {
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
));
|
||||
|
||||
// `{ let _result = ...; _result }`
|
||||
// Underscore prevents an `unused_variables` lint if the head diverges.
|
||||
let result_ident = self.str_to_ident("_result");
|
||||
let (let_stmt, let_stmt_binding) =
|
||||
self.stmt_let(e.span, false, result_ident, match_expr);
|
||||
|
||||
let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding));
|
||||
let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result)));
|
||||
// Add the attributes to the outer returned expr node.
|
||||
return self.expr_block(block, e.attrs.clone());
|
||||
// This is effectively `{ let _result = ...; _result }`.
|
||||
// The construct was introduced in #21984.
|
||||
// FIXME(60253): Is this still necessary?
|
||||
// Also, add the attributes to the outer returned expr node.
|
||||
return self.expr_use(head_sp, match_expr, e.attrs.clone())
|
||||
}
|
||||
|
||||
// Desugar `ExprKind::Try`
|
||||
@ -5117,6 +5112,17 @@ impl<'a> LoweringContext<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Wrap the given `expr` in `hir::ExprKind::Use`.
|
||||
///
|
||||
/// In terms of drop order, it has the same effect as
|
||||
/// wrapping `expr` in `{ let _t = $expr; _t }` but
|
||||
/// should provide better compile-time performance.
|
||||
///
|
||||
/// The drop order can be important in e.g. `if expr { .. }`.
|
||||
fn expr_use(&mut self, span: Span, expr: P<hir::Expr>, attrs: ThinVec<Attribute>) -> hir::Expr {
|
||||
self.expr(span, hir::ExprKind::Use(expr), attrs)
|
||||
}
|
||||
|
||||
fn expr_match(
|
||||
&mut self,
|
||||
span: Span,
|
||||
@ -5172,25 +5178,6 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn stmt_let(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
mutbl: bool,
|
||||
ident: Ident,
|
||||
ex: P<hir::Expr>,
|
||||
) -> (hir::Stmt, hir::HirId) {
|
||||
let (pat, pat_hid) = if mutbl {
|
||||
self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable)
|
||||
} else {
|
||||
self.pat_ident(sp, ident)
|
||||
};
|
||||
|
||||
(
|
||||
self.stmt_let_pat(sp, Some(ex), pat, hir::LocalSource::Normal),
|
||||
pat_hid,
|
||||
)
|
||||
}
|
||||
|
||||
fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
|
||||
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
|
||||
}
|
||||
|
@ -1366,6 +1366,7 @@ impl Expr {
|
||||
ExprKind::Unary(..) => ExprPrecedence::Unary,
|
||||
ExprKind::Lit(_) => ExprPrecedence::Lit,
|
||||
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
ExprKind::Use(ref expr, ..) => expr.precedence(),
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::While(..) => ExprPrecedence::While,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
@ -1437,6 +1438,7 @@ impl Expr {
|
||||
ExprKind::Binary(..) |
|
||||
ExprKind::Yield(..) |
|
||||
ExprKind::Cast(..) |
|
||||
ExprKind::Use(..) |
|
||||
ExprKind::Err => {
|
||||
false
|
||||
}
|
||||
@ -1486,6 +1488,10 @@ pub enum ExprKind {
|
||||
Cast(P<Expr>, P<Ty>),
|
||||
/// A type reference (e.g., `Foo`).
|
||||
Type(P<Expr>, P<Ty>),
|
||||
/// Semantically equivalent to `{ let _t = expr; _t }`.
|
||||
/// Maps directly to `hair::ExprKind::Use`.
|
||||
/// Only exists to tweak the drop order in HIR.
|
||||
Use(P<Expr>),
|
||||
/// An `if` block, with an optional else block.
|
||||
///
|
||||
/// I.e., `if <expr> { <expr> } else { <expr> }`.
|
||||
|
@ -995,23 +995,32 @@ impl<'a> State<'a> {
|
||||
self.ann.post(self, AnnNode::SubItem(ii.hir_id))
|
||||
}
|
||||
|
||||
pub fn print_local(
|
||||
&mut self,
|
||||
init: Option<&hir::Expr>,
|
||||
decl: impl Fn(&mut Self) -> io::Result<()>
|
||||
) -> io::Result<()> {
|
||||
self.space_if_not_bol()?;
|
||||
self.ibox(indent_unit)?;
|
||||
self.word_nbsp("let")?;
|
||||
|
||||
self.ibox(indent_unit)?;
|
||||
decl(self)?;
|
||||
self.end()?;
|
||||
|
||||
if let Some(ref init) = init {
|
||||
self.nbsp()?;
|
||||
self.word_space("=")?;
|
||||
self.print_expr(&init)?;
|
||||
}
|
||||
self.end()
|
||||
}
|
||||
|
||||
pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
|
||||
self.maybe_print_comment(st.span.lo())?;
|
||||
match st.node {
|
||||
hir::StmtKind::Local(ref loc) => {
|
||||
self.space_if_not_bol()?;
|
||||
self.ibox(indent_unit)?;
|
||||
self.word_nbsp("let")?;
|
||||
|
||||
self.ibox(indent_unit)?;
|
||||
self.print_local_decl(&loc)?;
|
||||
self.end()?;
|
||||
if let Some(ref init) = loc.init {
|
||||
self.nbsp()?;
|
||||
self.word_space("=")?;
|
||||
self.print_expr(&init)?;
|
||||
}
|
||||
self.end()?
|
||||
self.print_local(loc.init.deref(), |this| this.print_local_decl(&loc))?;
|
||||
}
|
||||
hir::StmtKind::Item(item) => {
|
||||
self.ann.nested(self, Nested::Item(item))?
|
||||
@ -1379,6 +1388,24 @@ impl<'a> State<'a> {
|
||||
self.word_space(":")?;
|
||||
self.print_type(&ty)?;
|
||||
}
|
||||
hir::ExprKind::Use(ref init) => {
|
||||
// Print `{`:
|
||||
self.cbox(indent_unit)?;
|
||||
self.ibox(0)?;
|
||||
self.bopen()?;
|
||||
|
||||
// Print `let _t = $init;`:
|
||||
let temp = ast::Ident::from_str("_t");
|
||||
self.print_local(Some(init), |this| this.print_ident(temp))?;
|
||||
self.s.word(";")?;
|
||||
|
||||
// Print `_t`:
|
||||
self.space_if_not_bol()?;
|
||||
self.print_ident(temp)?;
|
||||
|
||||
// Print `}`:
|
||||
self.bclose_maybe_open(expr.span, indent_unit, true)?;
|
||||
}
|
||||
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
||||
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#![feature(box_syntax)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(inner_deref)]
|
||||
#![cfg_attr(windows, feature(libc))]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
|
@ -521,6 +521,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
self.consume_expr(&base);
|
||||
}
|
||||
|
||||
hir::ExprKind::Use(ref expr) => {
|
||||
self.consume_expr(&expr);
|
||||
}
|
||||
|
||||
hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => {
|
||||
if self.mc.tables.is_method_call(expr) {
|
||||
self.consume_expr(lhs);
|
||||
|
@ -521,6 +521,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
hir::ExprKind::Binary(..) |
|
||||
hir::ExprKind::AddrOf(..) |
|
||||
hir::ExprKind::Cast(..) |
|
||||
hir::ExprKind::Use(..) |
|
||||
hir::ExprKind::Unary(..) |
|
||||
hir::ExprKind::Break(..) |
|
||||
hir::ExprKind::Continue(_) |
|
||||
@ -1221,6 +1222,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
hir::ExprKind::AddrOf(_, ref e) |
|
||||
hir::ExprKind::Cast(ref e, _) |
|
||||
hir::ExprKind::Type(ref e, _) |
|
||||
hir::ExprKind::Use(ref e) |
|
||||
hir::ExprKind::Unary(_, ref e) |
|
||||
hir::ExprKind::Yield(ref e) |
|
||||
hir::ExprKind::Repeat(ref e, _) => {
|
||||
@ -1524,9 +1526,9 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
|
||||
hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
|
||||
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
|
||||
hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) |
|
||||
hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) |
|
||||
hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
|
||||
hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) |
|
||||
hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) |
|
||||
hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
|
||||
hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
|
||||
hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
|
||||
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {
|
||||
|
@ -678,7 +678,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) |
|
||||
hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) |
|
||||
hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
|
||||
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) |
|
||||
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) |
|
||||
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) |
|
||||
hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
|
||||
hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
|
||||
|
@ -909,6 +909,12 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
}
|
||||
|
||||
hir::ExprKind::Use(ref expr) => {
|
||||
// `Use(expr)` does not denote a conditional scope.
|
||||
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
|
||||
terminating(expr.hir_id.local_id);
|
||||
}
|
||||
|
||||
hir::ExprKind::AssignOp(..) | hir::ExprKind::Index(..) |
|
||||
hir::ExprKind::Unary(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
|
||||
// FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
|
||||
|
@ -2156,61 +2156,95 @@ impl<'p, 'tcx> FusedIterator for PlaceProjectionsIter<'p, 'tcx> {}
|
||||
|
||||
impl<'tcx> Debug for Place<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
use self::Place::*;
|
||||
self.iterate(|_place_base, place_projections| {
|
||||
// FIXME: remove this collect once we have migrated to slices
|
||||
let projs_vec: Vec<_> = place_projections.collect();
|
||||
for projection in projs_vec.iter().rev() {
|
||||
match projection.elem {
|
||||
ProjectionElem::Downcast(_, _) |
|
||||
ProjectionElem::Field(_, _) => {
|
||||
write!(fmt, "(").unwrap();
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, "(*").unwrap();
|
||||
}
|
||||
ProjectionElem::Index(_) |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
ProjectionElem::Subslice { .. } => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
match *self {
|
||||
Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id),
|
||||
Base(PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) })) => {
|
||||
write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id)),
|
||||
ty
|
||||
)
|
||||
},
|
||||
Base(PlaceBase::Static(
|
||||
box self::Static { ty, kind: StaticKind::Promoted(promoted) })
|
||||
) => {
|
||||
write!(
|
||||
fmt,
|
||||
"({:?}: {:?})",
|
||||
promoted,
|
||||
ty
|
||||
)
|
||||
},
|
||||
Projection(ref data) => match data.elem {
|
||||
ProjectionElem::Downcast(Some(name), _index) => {
|
||||
write!(fmt, "({:?} as {})", data.base, name)
|
||||
self.iterate(|place_base, place_projections| {
|
||||
match place_base {
|
||||
PlaceBase::Local(id) => {
|
||||
write!(fmt, "{:?}", id)?;
|
||||
}
|
||||
ProjectionElem::Downcast(None, index) => {
|
||||
write!(fmt, "({:?} as variant#{:?})", data.base, index)
|
||||
PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => {
|
||||
write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.def_path_str(*def_id)),
|
||||
ty
|
||||
)?;
|
||||
},
|
||||
PlaceBase::Static(
|
||||
box self::Static { ty, kind: StaticKind::Promoted(promoted) }
|
||||
) => {
|
||||
write!(
|
||||
fmt,
|
||||
"({:?}: {:?})",
|
||||
promoted,
|
||||
ty
|
||||
)?;
|
||||
},
|
||||
}
|
||||
|
||||
for projection in place_projections {
|
||||
match projection.elem {
|
||||
ProjectionElem::Downcast(Some(name), _index) => {
|
||||
write!(fmt, " as {})", name)?;
|
||||
}
|
||||
ProjectionElem::Downcast(None, index) => {
|
||||
write!(fmt, " as variant#{:?})", index)?;
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, ")")?;
|
||||
}
|
||||
ProjectionElem::Field(field, ty) => {
|
||||
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
|
||||
}
|
||||
ProjectionElem::Index(ref index) => {
|
||||
write!(fmt, "[{:?}]", index)?;
|
||||
}
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length,
|
||||
from_end: false,
|
||||
} => {
|
||||
write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
|
||||
}
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length,
|
||||
from_end: true,
|
||||
} => {
|
||||
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if to == 0 => {
|
||||
write!(fmt, "[{:?}:]", from)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if from == 0 => {
|
||||
write!(fmt, "[:-{:?}]", to)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
write!(fmt, "[{:?}:-{:?}]", from, to)?;
|
||||
}
|
||||
}
|
||||
ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base),
|
||||
ProjectionElem::Field(field, ty) => {
|
||||
write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty)
|
||||
}
|
||||
ProjectionElem::Index(ref index) => write!(fmt, "{:?}[{:?}]", data.base, index),
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length,
|
||||
from_end: false,
|
||||
} => write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length),
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length,
|
||||
from_end: true,
|
||||
} => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length),
|
||||
ProjectionElem::Subslice { from, to } if to == 0 => {
|
||||
write!(fmt, "{:?}[{:?}:]", data.base, from)
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if from == 0 => {
|
||||
write!(fmt, "{:?}[:-{:?}]", data.base, to)
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
write!(fmt, "{:?}[{:?}:-{:?}]", data.base, from, to)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2505,16 +2505,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
ty::Closure(def_id, substs) => {
|
||||
let trait_id = obligation.predicate.def_id();
|
||||
let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait();
|
||||
let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait();
|
||||
if is_copy_trait || is_clone_trait {
|
||||
Where(ty::Binder::bind(
|
||||
substs.upvar_tys(def_id, self.tcx()).collect(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
// (*) binder moved here
|
||||
Where(ty::Binder::bind(
|
||||
substs.upvar_tys(def_id, self.tcx()).collect(),
|
||||
))
|
||||
}
|
||||
|
||||
ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
|
||||
|
@ -542,18 +542,13 @@ declare_lint! {
|
||||
"detects missing implementations of fmt::Debug"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MissingDebugImplementations {
|
||||
impling_types: Option<HirIdSet>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
|
||||
|
||||
impl MissingDebugImplementations {
|
||||
pub fn new() -> MissingDebugImplementations {
|
||||
MissingDebugImplementations { impling_types: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
|
||||
fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
|
||||
if !cx.access_levels.is_reachable(item.hir_id) {
|
||||
@ -1285,6 +1280,7 @@ declare_lint! {
|
||||
"`...` range patterns are deprecated"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EllipsisInclusiveRangePatterns {
|
||||
/// If `Some(_)`, suppress all subsequent pattern
|
||||
/// warnings for better diagnostics.
|
||||
@ -1293,14 +1289,6 @@ pub struct EllipsisInclusiveRangePatterns {
|
||||
|
||||
impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
|
||||
|
||||
impl EllipsisInclusiveRangePatterns {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
node_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for EllipsisInclusiveRangePatterns {
|
||||
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
|
||||
if self.node_id.is_some() {
|
||||
|
@ -94,7 +94,7 @@ macro_rules! early_lint_passes {
|
||||
UnusedImportBraces: UnusedImportBraces,
|
||||
UnsafeCode: UnsafeCode,
|
||||
AnonymousParameters: AnonymousParameters,
|
||||
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::new(),
|
||||
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
|
||||
NonCamelCaseTypes: NonCamelCaseTypes,
|
||||
DeprecatedAttr: DeprecatedAttr::new(),
|
||||
]);
|
||||
@ -132,7 +132,7 @@ macro_rules! late_lint_passes {
|
||||
// Depends on access levels
|
||||
// FIXME: Turn the computation of types which implement Debug into a query
|
||||
// and change this to a module lint pass
|
||||
MissingDebugImplementations: MissingDebugImplementations::new(),
|
||||
MissingDebugImplementations: MissingDebugImplementations::default(),
|
||||
]);
|
||||
)
|
||||
}
|
||||
|
@ -759,6 +759,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Use(ref source) => {
|
||||
ExprKind::Use { source: source.to_ref() }
|
||||
}
|
||||
hir::ExprKind::Box(ref value) => {
|
||||
ExprKind::Box {
|
||||
value: value.to_ref(),
|
||||
|
@ -436,7 +436,9 @@ fn check_expr_kind<'a, 'tcx>(
|
||||
hir::ExprKind::Err => Promotable,
|
||||
|
||||
hir::ExprKind::AddrOf(_, ref expr) |
|
||||
hir::ExprKind::Repeat(ref expr, _) => {
|
||||
hir::ExprKind::Repeat(ref expr, _) |
|
||||
hir::ExprKind::Type(ref expr, _) |
|
||||
hir::ExprKind::Use(ref expr) => {
|
||||
v.check_expr(&expr)
|
||||
}
|
||||
|
||||
@ -483,10 +485,6 @@ fn check_expr_kind<'a, 'tcx>(
|
||||
array_result
|
||||
}
|
||||
|
||||
hir::ExprKind::Type(ref expr, ref _ty) => {
|
||||
v.check_expr(&expr)
|
||||
}
|
||||
|
||||
hir::ExprKind::Tup(ref hirvec) => {
|
||||
let mut tup_result = Promotable;
|
||||
for index in hirvec.iter() {
|
||||
@ -495,7 +493,6 @@ fn check_expr_kind<'a, 'tcx>(
|
||||
tup_result
|
||||
}
|
||||
|
||||
|
||||
// Conditional control flow (possible to implement).
|
||||
hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => {
|
||||
// Compute the most demanding borrow from all the arms'
|
||||
|
@ -1642,6 +1642,19 @@ fn main() {
|
||||
```
|
||||
"##,
|
||||
|
||||
E0671: r##"
|
||||
Const parameters cannot depend on type parameters.
|
||||
The following is therefore invalid:
|
||||
```compile_fail,E0671
|
||||
#![feature(const_generics)]
|
||||
|
||||
fn const_id<T, const N: T>() -> T { // error: const parameter
|
||||
// depends on type parameter
|
||||
N
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
|
@ -185,6 +185,8 @@ enum ResolutionError<'a> {
|
||||
BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
|
||||
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
|
||||
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
|
||||
/// Error E0671: const parameter cannot depend on type parameter.
|
||||
ConstParamDependentOnTypeParam,
|
||||
}
|
||||
|
||||
/// Combines an error with provided span and emits it.
|
||||
@ -440,6 +442,16 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
|
||||
span, "defaulted type parameters cannot be forward declared".to_string());
|
||||
err
|
||||
}
|
||||
ResolutionError::ConstParamDependentOnTypeParam => {
|
||||
let mut err = struct_span_err!(
|
||||
resolver.session,
|
||||
span,
|
||||
E0671,
|
||||
"const parameters cannot depend on type parameters"
|
||||
);
|
||||
err.span_label(span, format!("const parameter depends on type parameter"));
|
||||
err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -915,6 +927,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||
}
|
||||
}));
|
||||
|
||||
// We also ban access to type parameters for use as the types of const parameters.
|
||||
let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
|
||||
const_ty_param_ban_rib.bindings.extend(generics.params.iter()
|
||||
.filter(|param| {
|
||||
if let GenericParamKind::Type { .. } = param.kind {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|param| (Ident::with_empty_ctxt(param.ident.name), Def::Err)));
|
||||
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
|
||||
@ -933,11 +957,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
|
||||
}
|
||||
GenericParamKind::Const { ref ty } => {
|
||||
self.ribs[TypeNS].push(const_ty_param_ban_rib);
|
||||
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
|
||||
self.visit_ty(ty);
|
||||
|
||||
const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -994,6 +1022,9 @@ enum RibKind<'a> {
|
||||
/// from the default of a type parameter because they're not declared
|
||||
/// before said type parameter. Also see the `visit_generics` override.
|
||||
ForwardTyParamBanRibKind,
|
||||
|
||||
/// We forbid the use of type parameters as the types of const parameters.
|
||||
TyParamAsConstParamTy,
|
||||
}
|
||||
|
||||
/// A single local scope.
|
||||
@ -3944,6 +3975,15 @@ impl<'a> Resolver<'a> {
|
||||
return Def::Err;
|
||||
}
|
||||
|
||||
// An invalid use of a type parameter as the type of a const parameter.
|
||||
if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind {
|
||||
if record_used {
|
||||
resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam);
|
||||
}
|
||||
assert_eq!(def, Def::Err);
|
||||
return Def::Err;
|
||||
}
|
||||
|
||||
match def {
|
||||
Def::Upvar(..) => {
|
||||
span_bug!(span, "unexpected {:?} in bindings", def)
|
||||
@ -3955,7 +3995,7 @@ impl<'a> Resolver<'a> {
|
||||
for rib in ribs {
|
||||
match rib.kind {
|
||||
NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) |
|
||||
ForwardTyParamBanRibKind => {
|
||||
ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
|
||||
// Nothing to do. Continue.
|
||||
}
|
||||
ClosureRibKind(function_id) => {
|
||||
@ -4013,7 +4053,7 @@ impl<'a> Resolver<'a> {
|
||||
match rib.kind {
|
||||
NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) |
|
||||
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
|
||||
ConstantItemRibKind => {
|
||||
ConstantItemRibKind | TyParamAsConstParamTy => {
|
||||
// Nothing to do. Continue.
|
||||
}
|
||||
ItemRibKind | FnItemRibKind => {
|
||||
|
@ -6,10 +6,42 @@ use rustc::traits::{
|
||||
};
|
||||
use rustc::ty;
|
||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use crate::lowering::Lower;
|
||||
use crate::generic_types;
|
||||
|
||||
/// Returns a predicate of the form
|
||||
/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...`
|
||||
/// where `Trait` is specified by `trait_def_id`.
|
||||
fn builtin_impl_clause(
|
||||
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||
ty: ty::Ty<'tcx>,
|
||||
nested: &[ty::Ty<'tcx>],
|
||||
trait_def_id: DefId
|
||||
) -> ProgramClause<'tcx> {
|
||||
ProgramClause {
|
||||
goal: ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
},
|
||||
}.lower(),
|
||||
hypotheses: tcx.mk_goals(
|
||||
nested.iter()
|
||||
.cloned()
|
||||
.map(|nested_ty| ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: tcx.mk_substs_trait(nested_ty, &[]),
|
||||
})
|
||||
.map(|trait_ref| ty::TraitPredicate { trait_ref })
|
||||
.map(|pred| GoalKind::DomainGoal(pred.lower()))
|
||||
.map(|goal_kind| tcx.mk_goal(goal_kind))
|
||||
),
|
||||
category: ProgramClauseCategory::Other,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn assemble_builtin_unsize_impls<'tcx>(
|
||||
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||
unsize_def_id: DefId,
|
||||
@ -93,26 +125,7 @@ crate fn assemble_builtin_sized_impls<'tcx>(
|
||||
clauses: &mut Vec<Clause<'tcx>>
|
||||
) {
|
||||
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
|
||||
let clause = ProgramClause {
|
||||
goal: ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef {
|
||||
def_id: sized_def_id,
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
},
|
||||
}.lower(),
|
||||
hypotheses: tcx.mk_goals(
|
||||
nested.iter()
|
||||
.cloned()
|
||||
.map(|nested_ty| ty::TraitRef {
|
||||
def_id: sized_def_id,
|
||||
substs: tcx.mk_substs_trait(nested_ty, &[]),
|
||||
})
|
||||
.map(|trait_ref| ty::TraitPredicate { trait_ref })
|
||||
.map(|pred| GoalKind::DomainGoal(pred.lower()))
|
||||
.map(|goal_kind| tcx.mk_goal(goal_kind))
|
||||
),
|
||||
category: ProgramClauseCategory::Other,
|
||||
};
|
||||
let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id);
|
||||
// Bind innermost bound vars that may exist in `ty` and `nested`.
|
||||
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
|
||||
};
|
||||
@ -124,6 +137,8 @@ crate fn assemble_builtin_sized_impls<'tcx>(
|
||||
ty::Int(..) |
|
||||
ty::Uint(..) |
|
||||
ty::Float(..) |
|
||||
ty::Infer(ty::IntVar(_)) |
|
||||
ty::Infer(ty::FloatVar(_)) |
|
||||
ty::Error |
|
||||
ty::Never => push_builtin_impl(ty, &[]),
|
||||
|
||||
@ -175,14 +190,11 @@ crate fn assemble_builtin_sized_impls<'tcx>(
|
||||
push_builtin_impl(adt, &sized_constraint);
|
||||
}
|
||||
|
||||
// Artificially trigger an ambiguity.
|
||||
ty::Infer(..) => {
|
||||
// Everybody can find at least two types to unify against:
|
||||
// general ty vars, int vars and float vars.
|
||||
// Artificially trigger an ambiguity by adding two possible types to
|
||||
// unify against.
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
push_builtin_impl(tcx.types.i32, &[]);
|
||||
push_builtin_impl(tcx.types.u32, &[]);
|
||||
push_builtin_impl(tcx.types.f32, &[]);
|
||||
push_builtin_impl(tcx.types.f64, &[]);
|
||||
}
|
||||
|
||||
ty::Projection(_projection_ty) => {
|
||||
@ -203,6 +215,108 @@ crate fn assemble_builtin_sized_impls<'tcx>(
|
||||
ty::Opaque(..) => (),
|
||||
|
||||
ty::Bound(..) |
|
||||
ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
|
||||
ty::GeneratorWitness(..) |
|
||||
ty::Infer(ty::FreshTy(_)) |
|
||||
ty::Infer(ty::FreshIntTy(_)) |
|
||||
ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn assemble_builtin_copy_clone_impls<'tcx>(
|
||||
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||
trait_def_id: DefId,
|
||||
ty: ty::Ty<'tcx>,
|
||||
clauses: &mut Vec<Clause<'tcx>>
|
||||
) {
|
||||
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
|
||||
let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id);
|
||||
// Bind innermost bound vars that may exist in `ty` and `nested`.
|
||||
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
|
||||
};
|
||||
|
||||
match &ty.sty {
|
||||
// Implementations provided in libcore.
|
||||
ty::Bool |
|
||||
ty::Char |
|
||||
ty::Int(..) |
|
||||
ty::Uint(..) |
|
||||
ty::Float(..) |
|
||||
ty::RawPtr(..) |
|
||||
ty::Never |
|
||||
ty::Ref(_, _, hir::MutImmutable) => (),
|
||||
|
||||
// Non parametric primitive types.
|
||||
ty::Infer(ty::IntVar(_)) |
|
||||
ty::Infer(ty::FloatVar(_)) |
|
||||
ty::Error => push_builtin_impl(ty, &[]),
|
||||
|
||||
// These implement `Copy`/`Clone` if their element types do.
|
||||
&ty::Array(_, length) => {
|
||||
let element_ty = generic_types::bound(tcx, 0);
|
||||
push_builtin_impl(tcx.mk_ty(ty::Array(element_ty, length)), &[element_ty]);
|
||||
}
|
||||
&ty::Tuple(type_list) => {
|
||||
let type_list = generic_types::type_list(tcx, type_list.len());
|
||||
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
|
||||
}
|
||||
&ty::Closure(def_id, ..) => {
|
||||
let closure_ty = generic_types::closure(tcx, def_id);
|
||||
let upvar_tys: Vec<_> = match &closure_ty.sty {
|
||||
ty::Closure(_, substs) => substs.upvar_tys(def_id, tcx).collect(),
|
||||
_ => bug!(),
|
||||
};
|
||||
push_builtin_impl(closure_ty, &upvar_tys);
|
||||
}
|
||||
|
||||
// These ones are always `Clone`.
|
||||
ty::FnPtr(fn_ptr) => {
|
||||
let fn_ptr = fn_ptr.skip_binder();
|
||||
let fn_ptr = generic_types::fn_ptr(
|
||||
tcx,
|
||||
fn_ptr.inputs_and_output.len(),
|
||||
fn_ptr.c_variadic,
|
||||
fn_ptr.unsafety,
|
||||
fn_ptr.abi
|
||||
);
|
||||
push_builtin_impl(fn_ptr, &[]);
|
||||
}
|
||||
&ty::FnDef(def_id, ..) => {
|
||||
push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
|
||||
}
|
||||
|
||||
// These depend on whatever user-defined impls might exist.
|
||||
ty::Adt(_, _) => (),
|
||||
|
||||
// Artificially trigger an ambiguity by adding two possible types to
|
||||
// unify against.
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
push_builtin_impl(tcx.types.i32, &[]);
|
||||
push_builtin_impl(tcx.types.f32, &[]);
|
||||
}
|
||||
|
||||
ty::Projection(_projection_ty) => {
|
||||
// FIXME: add builtin impls from the associated type values found in
|
||||
// trait impls of `projection_ty.trait_ref(tcx)`.
|
||||
}
|
||||
|
||||
// The `Copy`/`Clone` bound can only come from the environment.
|
||||
ty::Param(..) |
|
||||
ty::Placeholder(..) |
|
||||
ty::UnnormalizedProjection(..) |
|
||||
ty::Opaque(..) => (),
|
||||
|
||||
// Definitely not `Copy`/`Clone`.
|
||||
ty::Dynamic(..) |
|
||||
ty::Foreign(..) |
|
||||
ty::Generator(..) |
|
||||
ty::Str |
|
||||
ty::Slice(..) |
|
||||
ty::Ref(_, _, hir::MutMutable) => (),
|
||||
|
||||
ty::Bound(..) |
|
||||
ty::GeneratorWitness(..) |
|
||||
ty::Infer(ty::FreshTy(_)) |
|
||||
ty::Infer(ty::FreshIntTy(_)) |
|
||||
ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
@ -96,8 +96,27 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() {
|
||||
assemble_builtin_copy_clone_impls(
|
||||
self.infcx.tcx,
|
||||
trait_predicate.def_id(),
|
||||
trait_predicate.self_ty(),
|
||||
&mut clauses
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() {
|
||||
// For all builtin impls, the conditions for `Copy` and
|
||||
// `Clone` are the same.
|
||||
assemble_builtin_copy_clone_impls(
|
||||
self.infcx.tcx,
|
||||
trait_predicate.def_id(),
|
||||
trait_predicate.self_ty(),
|
||||
&mut clauses
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: we need to add special rules for other builtin impls:
|
||||
// * `Copy` / `Clone`
|
||||
// * `Generator`
|
||||
// * `FnOnce` / `FnMut` / `Fn`
|
||||
// * trait objects
|
||||
|
@ -4533,6 +4533,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.check_expr_eq_type(&e, ty);
|
||||
ty
|
||||
}
|
||||
ExprKind::Use(ref e) => {
|
||||
self.check_expr_with_expectation(e, expected)
|
||||
}
|
||||
ExprKind::Array(ref args) => {
|
||||
let uty = expected.to_option(self).and_then(|uty| {
|
||||
match uty.sty {
|
||||
|
@ -443,13 +443,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
) -> bool /* did we suggest to call a function because of missing parenthesis? */ {
|
||||
err.span_label(span, ty.to_string());
|
||||
if let FnDef(def_id, _) = ty.sty {
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let hir_id = match self.tcx.hir().as_local_hir_id(def_id) {
|
||||
Some(hir_id) => hir_id,
|
||||
None => return false,
|
||||
};
|
||||
if self.tcx.has_typeck_tables(def_id) == false {
|
||||
return false;
|
||||
}
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
let fn_sig = {
|
||||
match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) {
|
||||
match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) {
|
||||
Some(f) => f.clone(),
|
||||
None => {
|
||||
bug!("No fn-sig entry for def_id={:?}", def_id);
|
||||
@ -458,11 +461,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
let other_ty = if let FnDef(def_id, _) = other_ty.sty {
|
||||
let hir_id = match self.tcx.hir().as_local_hir_id(def_id) {
|
||||
Some(hir_id) => hir_id,
|
||||
None => return false,
|
||||
};
|
||||
if self.tcx.has_typeck_tables(def_id) == false {
|
||||
return false;
|
||||
}
|
||||
let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) {
|
||||
match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) {
|
||||
Some(f) => f.clone().output(),
|
||||
None => {
|
||||
bug!("No fn-sig entry for def_id={:?}", def_id);
|
||||
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
pulldown-cmark = { version = "0.4.1", default-features = false }
|
||||
minifier = "0.0.29"
|
||||
minifier = "0.0.30"
|
||||
tempfile = "3"
|
||||
parking_lot = "0.7"
|
||||
|
@ -351,6 +351,9 @@ impl Options {
|
||||
.unwrap_or_else(|| PathBuf::from("doc"));
|
||||
let mut cfgs = matches.opt_strs("cfg");
|
||||
cfgs.push("rustdoc".to_string());
|
||||
if should_test {
|
||||
cfgs.push("test".to_string());
|
||||
}
|
||||
|
||||
let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));
|
||||
|
||||
|
@ -951,40 +951,15 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||
key: &str,
|
||||
for_search_index: bool,
|
||||
) -> io::Result<(Vec<String>, Vec<String>, Vec<String>)> {
|
||||
use minifier::js;
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut krates = Vec::new();
|
||||
let mut variables = Vec::new();
|
||||
|
||||
let mut krate = krate.to_owned();
|
||||
|
||||
if path.exists() {
|
||||
for line in BufReader::new(File::open(path)?).lines() {
|
||||
let line = line?;
|
||||
if for_search_index && line.starts_with("var R") {
|
||||
variables.push(line.clone());
|
||||
// We need to check if the crate name has been put into a variable as well.
|
||||
let tokens: js::Tokens<'_> = js::simple_minify(&line)
|
||||
.into_iter()
|
||||
.filter(js::clean_token)
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
let mut pos = 0;
|
||||
while pos < tokens.len() {
|
||||
if let Some((var_pos, Some(value_pos))) =
|
||||
js::get_variable_name_and_value_positions(&tokens, pos) {
|
||||
if let Some(s) = tokens.0[value_pos].get_string() {
|
||||
if &s[1..s.len() - 1] == krate {
|
||||
if let Some(var) = tokens[var_pos].get_other() {
|
||||
krate = var.to_owned();
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if !line.starts_with(key) {
|
||||
@ -1340,10 +1315,20 @@ fn write_minify_replacer<W: Write>(
|
||||
.into();
|
||||
tokens.apply(|f| {
|
||||
// We add a backline after the newly created variables.
|
||||
minifier::js::aggregate_strings_into_array_with_separation(
|
||||
minifier::js::aggregate_strings_into_array_with_separation_filter(
|
||||
f,
|
||||
"R",
|
||||
Token::Char(ReservedChar::Backline),
|
||||
// This closure prevents crates' names from being aggregated.
|
||||
//
|
||||
// The point here is to check if the string is preceded by '[' and
|
||||
// "searchIndex". If so, it means this is a crate name and that it
|
||||
// shouldn't be aggregated.
|
||||
|tokens, pos| {
|
||||
pos < 2 ||
|
||||
!tokens[pos - 1].is_char(ReservedChar::OpenBracket) ||
|
||||
tokens[pos - 2].get_other() != Some("searchIndex")
|
||||
}
|
||||
)
|
||||
})
|
||||
.to_string()
|
||||
@ -1358,7 +1343,8 @@ fn write_minify_replacer<W: Write>(
|
||||
/// static HTML tree. Each component in the cleaned path will be passed as an
|
||||
/// argument to `f`. The very last component of the path (ie the file name) will
|
||||
/// be passed to `f` if `keep_filename` is true, and ignored otherwise.
|
||||
fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) where
|
||||
fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
|
||||
where
|
||||
F: FnMut(&OsStr),
|
||||
{
|
||||
// make it relative, if possible
|
||||
@ -1470,11 +1456,11 @@ impl<'a> SourceCollector<'a> {
|
||||
let mut href = String::new();
|
||||
clean_srcpath(&self.scx.src_root, &p, false, |component| {
|
||||
cur.push(component);
|
||||
fs::create_dir_all(&cur).unwrap();
|
||||
root_path.push_str("../");
|
||||
href.push_str(&component.to_string_lossy());
|
||||
href.push('/');
|
||||
});
|
||||
fs::create_dir_all(&cur)?;
|
||||
let mut fname = p.file_name()
|
||||
.expect("source has no filename")
|
||||
.to_os_string();
|
||||
@ -1483,7 +1469,7 @@ impl<'a> SourceCollector<'a> {
|
||||
href.push_str(&fname.to_string_lossy());
|
||||
|
||||
let mut w = BufWriter::new(File::create(&cur)?);
|
||||
let title = format!("{} -- source", cur.file_name().unwrap()
|
||||
let title = format!("{} -- source", cur.file_name().expect("failed to get file name")
|
||||
.to_string_lossy());
|
||||
let desc = format!("Source to the Rust file `{}`.", filename);
|
||||
let page = layout::Page {
|
||||
|
@ -403,6 +403,7 @@ declare_features! (
|
||||
(active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
|
||||
(active, movbe_target_feature, "1.34.0", Some(44839), None),
|
||||
(active, rtm_target_feature, "1.35.0", Some(44839), None),
|
||||
(active, f16c_target_feature, "1.36.0", Some(44839), None),
|
||||
|
||||
// Allows macro invocations on modules expressions and statements and
|
||||
// procedural macros to expand to non-items.
|
||||
@ -2258,32 +2259,32 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
|
||||
if let Some(allowed) = allow_features.as_ref() {
|
||||
if allowed.iter().find(|f| *f == name.as_str()).is_none() {
|
||||
span_err!(span_handler, mi.span(), E0725,
|
||||
"the feature `{}` is not in the list of allowed features",
|
||||
name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
set(&mut features, mi.span());
|
||||
features.declared_lang_features.push((name, mi.span(), None));
|
||||
continue
|
||||
}
|
||||
|
||||
let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
|
||||
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
|
||||
if let Some((.., reason)) = removed.or(stable_removed) {
|
||||
feature_removed(span_handler, mi.span(), *reason);
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) {
|
||||
let since = Some(Symbol::intern(since));
|
||||
features.declared_lang_features.push((name, mi.span(), since));
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(allowed) = allow_features.as_ref() {
|
||||
if allowed.iter().find(|f| *f == name.as_str()).is_none() {
|
||||
span_err!(span_handler, mi.span(), E0725,
|
||||
"the feature `{}` is not in the list of allowed features",
|
||||
name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
|
||||
set(&mut features, mi.span());
|
||||
features.declared_lang_features.push((name, mi.span(), None));
|
||||
continue;
|
||||
}
|
||||
|
||||
features.declared_lib_features.push((name, mi.span()));
|
||||
|
43
src/test/run-pass/chalkify/builtin-copy-clone.rs
Normal file
43
src/test/run-pass/chalkify/builtin-copy-clone.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
// Test that `Clone` is correctly implemented for builtin types.
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct S(i32);
|
||||
|
||||
fn test_clone<T: Clone>(arg: T) {
|
||||
let _ = arg.clone();
|
||||
}
|
||||
|
||||
fn test_copy<T: Copy>(arg: T) {
|
||||
let _ = arg;
|
||||
let _ = arg;
|
||||
}
|
||||
|
||||
fn test_copy_clone<T: Copy + Clone>(arg: T) {
|
||||
test_copy(arg);
|
||||
test_clone(arg);
|
||||
}
|
||||
|
||||
fn foo() { }
|
||||
|
||||
fn main() {
|
||||
test_copy_clone(foo);
|
||||
let f: fn() = foo;
|
||||
test_copy_clone(f);
|
||||
// FIXME: add closures when they're considered WF
|
||||
test_copy_clone([1; 56]);
|
||||
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
|
||||
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1));
|
||||
test_copy_clone(());
|
||||
test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ()));
|
||||
|
||||
let a = (
|
||||
(S(1), S(0)),
|
||||
(
|
||||
(S(0), S(0), S(1)),
|
||||
S(0)
|
||||
)
|
||||
);
|
||||
test_copy_clone(a);
|
||||
}
|
19
src/test/rustdoc-ui/cfg-test.rs
Normal file
19
src/test/rustdoc-ui/cfg-test.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// compile-pass
|
||||
// compile-flags:--test
|
||||
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
|
||||
|
||||
/// this doctest will be ignored:
|
||||
///
|
||||
/// ```
|
||||
/// assert!(false);
|
||||
/// ```
|
||||
#[cfg(not(test))]
|
||||
pub struct Foo;
|
||||
|
||||
/// this doctest will be tested:
|
||||
///
|
||||
/// ```
|
||||
/// assert!(true);
|
||||
/// ```
|
||||
#[cfg(test)]
|
||||
pub struct Foo;
|
6
src/test/rustdoc-ui/cfg-test.stdout
Normal file
6
src/test/rustdoc-ui/cfg-test.stdout
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
running 1 test
|
||||
test $DIR/cfg-test.rs - Foo (line 15) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
|
@ -1,3 +1,5 @@
|
||||
// aux-build:all-item-types.rs
|
||||
// build-aux-docs
|
||||
// compile-flags: -Z unstable-options --enable-index-page
|
||||
|
||||
#![crate_name = "foo"]
|
||||
@ -5,4 +7,5 @@
|
||||
// @has foo/../index.html
|
||||
// @has - '//span[@class="in-band"]' 'List of all crates'
|
||||
// @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo'
|
||||
// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types'
|
||||
pub struct Foo;
|
||||
|
@ -0,0 +1,6 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
|
||||
//~^ ERROR const parameters cannot depend on type parameters
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,19 @@
|
||||
error[E0671]: const parameters cannot depend on type parameters
|
||||
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
|
||||
|
|
||||
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
|
||||
| ^ const parameter depends on type parameter
|
||||
|
||||
error[E0658]: const generics are unstable
|
||||
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
|
||||
|
|
||||
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
|
||||
| ^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
|
||||
= help: add #![feature(const_generics)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0658, E0671.
|
||||
For more information about an error, try `rustc --explain E0658`.
|
@ -0,0 +1,13 @@
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
// Currently, const parameters cannot depend on type parameters, because there is no way to
|
||||
// enforce the `structural_match` property on an arbitrary type parameter. This restriction
|
||||
// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more
|
||||
// details.
|
||||
|
||||
pub struct Dependent<T, const X: T>([(); X]);
|
||||
//~^ ERROR const parameters cannot depend on type parameters
|
||||
//~^^ ERROR parameter `T` is never used
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,24 @@
|
||||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error[E0671]: const parameters cannot depend on type parameters
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
|
||||
|
|
||||
LL | pub struct Dependent<T, const X: T>([(); X]);
|
||||
| ^ const parameter depends on type parameter
|
||||
|
||||
error[E0392]: parameter `T` is never used
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:9:22
|
||||
|
|
||||
LL | pub struct Dependent<T, const X: T>([(); X]);
|
||||
| ^ unused parameter
|
||||
|
|
||||
= help: consider removing `T` or using a marker such as `std::marker::PhantomData`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0392, E0671.
|
||||
For more information about an error, try `rustc --explain E0392`.
|
@ -7,4 +7,6 @@
|
||||
|
||||
#![feature(lang_items)] //~ ERROR
|
||||
|
||||
#![feature(unknown_stdlib_feature)] //~ ERROR
|
||||
|
||||
fn main() {}
|
||||
|
@ -16,6 +16,12 @@ error[E0725]: the feature `lang_items` is not in the list of allowed features
|
||||
LL | #![feature(lang_items)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features
|
||||
--> $DIR/allow-features-empty.rs:10:12
|
||||
|
|
||||
LL | #![feature(unknown_stdlib_feature)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0725`.
|
||||
|
@ -7,4 +7,6 @@
|
||||
|
||||
#![feature(lang_items)]
|
||||
|
||||
#![feature(unknown_stdlib_feature)] //~ ERROR
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,6 +4,12 @@ error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed f
|
||||
LL | #![feature(rustc_const_unstable)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features
|
||||
--> $DIR/allow-features.rs:10:12
|
||||
|
|
||||
LL | #![feature(unknown_stdlib_feature)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0725`.
|
||||
|
@ -24,6 +24,7 @@
|
||||
// gate-test-cmpxchg16b_target_feature
|
||||
// gate-test-movbe_target_feature
|
||||
// gate-test-rtm_target_feature
|
||||
// gate-test-f16c_target_feature
|
||||
// min-llvm-version 6.0
|
||||
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0658]: the target feature `avx512bw` is currently unstable
|
||||
--> $DIR/target-feature-gate.rs:29:18
|
||||
--> $DIR/target-feature-gate.rs:30:18
|
||||
|
|
||||
LL | #[target_feature(enable = "avx512bw")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
Loading…
x
Reference in New Issue
Block a user