diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9be73cf3c6d16..e684ccfeeb7ed 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1636,6 +1636,9 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { Error0644("closure/generator type that references itself") } + TypeError::IntrinsicCast => { + Error0308("cannot coerce intrinsics to function pointers") + } _ => Error0308("mismatched types"), }, } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e240e0df8b948..17c9e520bcea2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2402,6 +2402,12 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_generic_adt(def_id, ty) } + #[inline] + pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Ty<'tcx> { + let def_id = self.require_lang_item(item, None); + self.mk_generic_adt(def_id, ty) + } + #[inline] pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index c70006b68d69a..fe8f94ab1d314 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -46,6 +46,8 @@ pub enum TypeError<'tcx> { ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), + + IntrinsicCast, } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -179,6 +181,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ConstMismatch(ref values) => { write!(f, "expected `{}`, found `{}`", values.expected, values.found) } + IntrinsicCast => { + write!(f, "cannot coerce intrinsics to function pointers") + } } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 649a5244728ba..ec7cf1a13c596 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -748,6 +748,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), + IntrinsicCast => IntrinsicCast, }) } } @@ -1338,6 +1339,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::Sorts)(x), (ty::error::TypeError::ExistentialMismatch)(x), (ty::error::TypeError::ConstMismatch)(x), + (ty::error::TypeError::IntrinsicCast), } } diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index 255af3122e70c..3bed5d81dc514 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -30,10 +30,8 @@ pub struct AnnotateSnippetEmitterWriter { impl Emitter for AnnotateSnippetEmitterWriter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { - let primary_span = db.span.clone(); let children = db.children.clone(); - // FIXME(#59346): Collect suggestions (see emitter.rs) - let suggestions: &[_] = &[]; + let (primary_span, suggestions) = self.primary_span_formatted(&db); // FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a0ce761cfa277..a298f9958f2d1 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -191,16 +191,25 @@ pub trait Emitter { fn should_show_explain(&self) -> bool { true } -} -impl Emitter for EmitterWriter { - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + /// Formats the substitutions of the primary_span + /// + /// The are a lot of conditions to this method, but in short: + /// + /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, + /// we format the `help` suggestion depending on the content of the + /// substitutions. In that case, we return the modified span only. + /// + /// * If the current `Diagnostic` has multiple suggestions, + /// we return the original `primary_span` and the original suggestions. + fn primary_span_formatted<'a>( + &mut self, + db: &'a DiagnosticBuilder<'_> + ) -> (MultiSpan, &'a [CodeSuggestion]) { let mut primary_span = db.span.clone(); - let mut children = db.children.clone(); - let mut suggestions: &[_] = &[]; - if let Some((sugg, rest)) = db.suggestions.split_first() { if rest.is_empty() && + // ^ if there is only one suggestion // don't display multi-suggestions as labels sugg.substitutions.len() == 1 && // don't display multipart suggestions as labels @@ -216,21 +225,34 @@ impl Emitter for EmitterWriter { { let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); let msg = if substitution.len() == 0 || sugg.style.hide_inline() { - // This substitution is only removal or we explicitly don't want to show the - // code inline, don't show it + // This substitution is only removal OR we explicitly don't want to show the + // code inline (`hide_inline`). Therefore, we don't show the substitution. format!("help: {}", sugg.msg) } else { + // Show the default suggestion text with the substitution format!("help: {}: `{}`", sugg.msg, substitution) }; primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); + + // We return only the modified primary_span + (primary_span, &[]) } else { // if there are multiple suggestions, print them all in full // to be consistent. We could try to figure out if we can // make one (or the first one) inline, but that would give // undue importance to a semi-random suggestion - suggestions = &db.suggestions; + (primary_span, &db.suggestions) } + } else { + (primary_span, &db.suggestions) } + } +} + +impl Emitter for EmitterWriter { + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + let mut children = db.children.clone(); + let (mut primary_span, suggestions) = self.primary_span_formatted(&db); self.fix_multispans_in_std_macros(&mut primary_span, &mut children, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f261fdc268b5b..e4b186736e2a1 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -405,13 +405,16 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } let arg = self.eval_operand(arg, source_info)?; + let oflo_check = self.tcx.sess.overflow_checks(); let val = self.use_ecx(source_info, |this| { let prim = this.ecx.read_immediate(arg)?; match op { UnOp::Neg => { - // Need to do overflow check here: For actual CTFE, MIR - // generation emits code that does this before calling the op. - if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { + // We check overflow in debug mode already + // so should only check in release mode. + if !oflo_check + && prim.layout.ty.is_signed() + && prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { throw_panic!(OverflowNeg) } } @@ -485,7 +488,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Scalar::from_bool(overflow).into(), ) } else { - if overflow { + // We check overflow in debug mode already + // so should only check in release mode. + if !self.tcx.sess.overflow_checks() && overflow { let err = err_panic!(Overflow(op)).into(); let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); return None; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index efc37cc04b212..7427ae9ce8de3 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -112,19 +112,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.diverges.set(pats_diverge); - let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + let arm_ty = if source_if && if_no_else && i != 0 && self.if_fallback_coercion( + expr.span, + &arms[0].body, + &mut coercion, + ) { + tcx.types.err + } else { + // Only call this if this is not an `if` expr with an expected type and no `else` + // clause to avoid duplicated type errors. (#60254) + self.check_expr_with_expectation(&arm.body, expected) + }; all_arms_diverge &= self.diverges.get(); - - let span = expr.span; - if source_if { let then_expr = &arms[0].body; match (i, if_no_else) { - (0, _) => coercion.coerce(self, &self.misc(span), &arm.body, arm_ty), - (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion), + (0, _) => coercion.coerce(self, &self.misc(expr.span), &arm.body, arm_ty), + (_, true) => {} // Handled above to avoid duplicated type errors (#60254). (_, _) => { let then_ty = prior_arm_ty.unwrap(); - let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty); + let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty); coercion.coerce(self, &cause, &arm.body, arm_ty); } } @@ -139,7 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), - _ => (span, ObligationCauseCode::MatchExpressionArm { + _ => (expr.span, ObligationCauseCode::MatchExpressionArm { arm_span, source: match_src, prior_arms: other_arms.clone(), @@ -180,16 +187,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Handle the fallback arm of a desugared if(-let) like a missing else. + /// + /// Returns `true` if there was an error forcing the coercion to the `()` type. fn if_fallback_coercion( &self, span: Span, then_expr: &'tcx hir::Expr, coercion: &mut CoerceMany<'tcx, '_, rustc::hir::Arm>, - ) { + ) -> bool { // If this `if` expr is the parent's function return expr, // the cause of the type coercion is the return type, point at it. (#25228) let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span); let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); + let mut error = false; coercion.coerce_forced_unit(self, &cause, &mut |err| { if let Some((span, msg)) = &ret_reason { err.span_label(*span, msg.as_str()); @@ -200,7 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.note("`if` expressions without `else` evaluate to `()`"); err.help("consider adding an `else` block that evaluates to the expected type"); + error = true; }, ret_reason.is_none()); + error } fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 55e7a10f1aaa4..c216cc92b1e58 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -40,6 +40,7 @@ use rustc::ty::{self, Ty, TypeFoldable, TypeAndMut}; use rustc::ty::subst::SubstsRef; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::cast::{CastKind, CastTy}; +use rustc::ty::error::TypeError; use rustc::middle::lang_items; use syntax::ast; use syntax_pos::Span; @@ -461,6 +462,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, fcx.tcx.mk_fn_ptr(f), AllowTwoPhase::No); + if let Err(TypeError::IntrinsicCast) = res { + return Err(CastError::IllegalCast); + } if res.is_err() { return Err(CastError::NonScalar); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 61b9c2a15ba16..f2e1a6e29d6fc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -70,6 +70,7 @@ use std::ops::Deref; use syntax::feature_gate; use syntax::symbol::sym; use syntax_pos; +use rustc_target::spec::abi::Abi; struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -689,6 +690,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.sty { ty::FnPtr(_) => { let a_sig = a.fn_sig(self.tcx); + // Intrinsics are not coercible to function pointers + if a_sig.abi() == Abi::RustIntrinsic || + a_sig.abi() == Abi::PlatformIntrinsic { + return Err(TypeError::IntrinsicCast); + } let InferOk { value: a_sig, mut obligations } = self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index a53fb12367d0e..fbaa9904d8303 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -12,7 +12,7 @@ use crate::check::fatally_break_rust; use crate::check::report_unexpected_variant_res; use crate::check::Needs; use crate::check::TupleArgumentsFlag::DontTupleArguments; -use crate::check::method::SelfSource; +use crate::check::method::{probe, SelfSource, MethodError}; use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; use crate::astconv::AstConv as _; @@ -29,6 +29,7 @@ use rustc::hir::def::{CtorKind, Res, DefKind}; use rustc::hir::ptr::P; use rustc::infer; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::middle::lang_items; use rustc::mir::interpret::GlobalId; use rustc::ty; use rustc::ty::adjustment::{ @@ -775,35 +776,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); - let method = match self.lookup_method(rcvr_t, - segment, - span, - expr, - rcvr) { + let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) { Ok(method) => { self.write_method_call(expr.hir_id, method); Ok(method) } Err(error) => { if segment.ident.name != kw::Invalid { - self.report_method_error(span, - rcvr_t, - segment.ident, - SelfSource::MethodCall(rcvr), - error, - Some(args)); + self.report_extended_method_error(segment, span, args, rcvr_t, error); } Err(()) } }; // Call the generic checker. - self.check_method_argument_types(span, - expr.span, - method, - &args[1..], - DontTupleArguments, - expected) + self.check_method_argument_types( + span, + expr.span, + method, + &args[1..], + DontTupleArguments, + expected, + ) + } + + fn report_extended_method_error( + &self, + segment: &hir::PathSegment, + span: Span, + args: &'tcx [hir::Expr], + rcvr_t: Ty<'tcx>, + error: MethodError<'tcx> + ) { + let rcvr = &args[0]; + let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| { + if let Ok(pick) = self.lookup_probe( + span, + segment.ident, + new_rcvr_t, + rcvr, + probe::ProbeScope::AllTraits, + ) { + err.span_label( + pick.item.ident.span, + &format!("the method is available for `{}` here", new_rcvr_t), + ); + } + }; + + if let Some(mut err) = self.report_method_error( + span, + rcvr_t, + segment.ident, + SelfSource::MethodCall(rcvr), + error, + Some(args), + ) { + if let ty::Adt(..) = rcvr_t.sty { + // Try alternative arbitrary self types that could fulfill this call. + // FIXME: probe for all types that *could* be arbitrary self-types, not + // just this whitelist. + let box_rcvr_t = self.tcx.mk_box(rcvr_t); + try_alt_rcvr(&mut err, box_rcvr_t); + let pin_rcvr_t = self.tcx.mk_lang_item( + rcvr_t, + lang_items::PinTypeLangItem, + ); + try_alt_rcvr(&mut err, pin_rcvr_t); + let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc); + try_alt_rcvr(&mut err, arc_rcvr_t); + let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc); + try_alt_rcvr(&mut err, rc_rcvr_t); + } + err.emit(); + } } fn check_expr_cast( @@ -1466,8 +1512,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let struct_variant_def = def.non_enum_variant(); let field_names = self.available_field_names(struct_variant_def); if !field_names.is_empty() { - err.note(&format!("available fields are: {}", - self.name_series_display(field_names))); + err.note(&format!( + "available fields are: {}", + self.name_series_display(field_names), + )); } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index a7e4f8e5c6289..1509c0f8a2196 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(result.callee) } - fn lookup_probe( + pub fn lookup_probe( &self, span: Span, method_name: ast::Ident, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 440e7e5d0e314..72e6f59715960 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -69,12 +69,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'b>, error: MethodError<'tcx>, args: Option<&'tcx [hir::Expr]>, - ) { + ) -> Option> { let orig_span = span; let mut span = span; // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { - return; + return None; } let print_disambiguation_help = | @@ -314,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } err.emit(); - return; + return None; } else { span = item_name.span; let mut err = struct_span_err!( @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - err.emit(); + return Some(err); } MethodError::Ambiguity(sources) => { @@ -573,6 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bug!("no return type expectations but got BadReturnType") } } + None } fn suggest_use_candidates(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cd041e80e7c9e..16903304a1427 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3580,7 +3580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { SelfSource::QPath(qself), error, None, - ); + ).map(|mut e| e.emit()); } result }); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 313734e3fdd6b..dcd32192ff384 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,6 +18,100 @@ use crate::clean::{self, PrimitiveType}; use crate::html::item_type::ItemType; use crate::html::render::{self, cache, CURRENT_DEPTH}; +pub trait Print { + fn print(self, buffer: &mut Buffer); +} + +impl Print for F + where F: FnOnce(&mut Buffer), +{ + fn print(self, buffer: &mut Buffer) { + (self)(buffer) + } +} + +impl Print for String { + fn print(self, buffer: &mut Buffer) { + buffer.write_str(&self); + } +} + +impl Print for &'_ str { + fn print(self, buffer: &mut Buffer) { + buffer.write_str(self); + } +} + +#[derive(Debug, Clone)] +pub struct Buffer { + for_html: bool, + buffer: String, +} + +impl Buffer { + crate fn empty_from(v: &Buffer) -> Buffer { + Buffer { + for_html: v.for_html, + buffer: String::new(), + } + } + + crate fn html() -> Buffer { + Buffer { + for_html: true, + buffer: String::new(), + } + } + + crate fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + crate fn into_inner(self) -> String { + self.buffer + } + + crate fn insert_str(&mut self, idx: usize, s: &str) { + self.buffer.insert_str(idx, s); + } + + crate fn push_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + + // Intended for consumption by write! and writeln! (std::fmt) but without + // the fmt::Result return type imposed by fmt::Write (and avoiding the trait + // import). + crate fn write_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + + // Intended for consumption by write! and writeln! (std::fmt) but without + // the fmt::Result return type imposed by fmt::Write (and avoiding the trait + // import). + crate fn write_fmt(&mut self, v: fmt::Arguments<'_>) { + use fmt::Write; + self.buffer.write_fmt(v).unwrap(); + } + + crate fn to_display(mut self, t: T) -> String { + t.print(&mut self); + self.into_inner() + } + + crate fn with_formatter) -> fmt::Result>(&mut self, t: T) { + self.from_display(display_fn(move |f| (t)(f))); + } + + crate fn from_display(&mut self, t: T) { + if self.for_html { + write!(self, "{}", t); + } else { + write!(self, "{:#}", t); + } + } +} + /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) #[derive(Copy, Clone)] @@ -200,11 +294,11 @@ impl<'a> fmt::Display for WhereClause<'a> { } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { clause.push_str(&format!("{}: {}", - lifetime, - bounds.iter() - .map(|b| b.to_string()) - .collect::>() - .join(" + "))); + lifetime, + bounds.iter() + .map(|b| b.to_string()) + .collect::>() + .join(" + "))); } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { @@ -778,9 +872,9 @@ impl fmt::Display for clean::Impl { // The difference from above is that trait is not hyperlinked. pub fn fmt_impl_for_trait_page(i: &clean::Impl, - f: &mut fmt::Formatter<'_>, - use_absolute: bool) -> fmt::Result { - fmt_impl(i, f, false, use_absolute) + f: &mut Buffer, + use_absolute: bool) { + f.with_formatter(|f| fmt_impl(i, f, false, use_absolute)) } impl fmt::Display for clean::Arguments { diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ae0bd1aafa8f1..56074f4ab1192 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,9 +1,8 @@ -use std::fmt; -use std::io; use std::path::PathBuf; use crate::externalfiles::ExternalHtml; use crate::html::render::SlashChecker; +use crate::html::format::{Buffer, Print}; #[derive(Clone)] pub struct Layout { @@ -11,6 +10,12 @@ pub struct Layout { pub favicon: String, pub external_html: ExternalHtml, pub krate: String, + /// The given user css file which allow to customize the generated + /// documentation theme. + pub css_file_extension: Option, + /// If false, the `select` element to have search filtering by crates on rendered docs + /// won't be generated. + pub generate_search_filter: bool, } pub struct Page<'a> { @@ -25,19 +30,15 @@ pub struct Page<'a> { pub static_extra_scripts: &'a [&'a str], } -pub fn render( - dst: &mut dyn io::Write, +pub fn render( layout: &Layout, page: &Page<'_>, - sidebar: &S, - t: &T, - css_file_extension: bool, + sidebar: S, + t: T, themes: &[PathBuf], - generate_search_filter: bool, -) -> io::Result<()> { +) -> String { let static_root_path = page.static_root_path.unwrap_or(page.root_path); - write!(dst, -"\ + format!("\ \ \ \ @@ -164,7 +165,7 @@ pub fn render( \ \ ", - css_extension = if css_file_extension { + css_extension = if layout.css_file_extension.is_some() { format!("", @@ -173,7 +174,7 @@ pub fn render( } else { String::new() }, - content = *t, + content = Buffer::html().to_display(t), static_root_path = static_root_path, root_path = page.root_path, css_class = page.css_class, @@ -207,7 +208,7 @@ pub fn render( in_header = layout.external_html.in_header, before_content = layout.external_html.before_content, after_content = layout.external_html.after_content, - sidebar = *sidebar, + sidebar = Buffer::html().to_display(sidebar), krate = layout.krate, themes = themes.iter() .filter_map(|t| t.file_stem()) @@ -228,7 +229,7 @@ pub fn render( root_path=page.root_path, extra_script=e) }).collect::(), - filter_crates=if generate_search_filter { + filter_crates=if layout.generate_search_filter { "" @@ -238,9 +239,9 @@ pub fn render( ) } -pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> { +pub fn redirect(url: &str) -> String { // ", - self.settings.iter() - .map(|(id, text, enabled)| { - format!("
\ - \ -
{}
\ -
", id, if *enabled { " checked" } else { "" }, text) - }) - .collect::(), - self.root_path, - self.suffix) - } + settings.iter() + .map(|(id, text, enabled)| { + format!("
\ + \ +
{}
\ +
", id, if *enabled { " checked" } else { "" }, text) + }) + .collect::(), + root_path, + suffix) } impl Context { @@ -1939,18 +1892,12 @@ impl Context { } else { String::new() }; - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &self.shared.layout, - &page, &sidebar, &all, - self.shared.css_file_extension.is_some(), - &self.shared.themes, - self.shared.generate_search_filter), - &final_file); - self.shared.fs.write(&final_file, &v)?; + let v = layout::render(&self.shared.layout, + &page, sidebar, |buf: &mut Buffer| all.print(buf), + &self.shared.themes); + self.shared.fs.write(&final_file, v.as_bytes())?; // Generating settings page. - let settings = Settings::new(self.shared.static_root_path.as_deref().unwrap_or("./"), - &self.shared.resource_suffix); page.title = "Rustdoc settings"; page.description = "Settings of Rustdoc"; page.root_path = "./"; @@ -1958,24 +1905,21 @@ impl Context { let mut themes = self.shared.themes.clone(); let sidebar = "

Settings

"; themes.push(PathBuf::from("settings.css")); - let layout = self.shared.layout.clone(); - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &layout, - &page, &sidebar, &settings, - self.shared.css_file_extension.is_some(), - &themes, - self.shared.generate_search_filter), - &settings_file); - self.shared.fs.write(&settings_file, &v)?; + let v = layout::render( + &self.shared.layout, + &page, sidebar, settings( + self.shared.static_root_path.as_deref().unwrap_or("./"), + &self.shared.resource_suffix + ), + &themes); + self.shared.fs.write(&settings_file, v.as_bytes())?; Ok(()) } fn render_item(&self, - writer: &mut dyn io::Write, it: &clean::Item, - pushname: bool) - -> io::Result<()> { + pushname: bool) -> String { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. CURRENT_DEPTH.with(|slot| { @@ -2022,12 +1966,10 @@ impl Context { } if !self.render_redirect_pages { - layout::render(writer, &self.shared.layout, &page, - &Sidebar{ cx: self, item: it }, - &Item{ cx: self, item: it }, - self.shared.css_file_extension.is_some(), - &self.shared.themes, - self.shared.generate_search_filter)?; + layout::render(&self.shared.layout, &page, + |buf: &mut _| print_sidebar(self, it, buf), + |buf: &mut _| print_item(self, it, buf), + &self.shared.themes) } else { let mut url = self.root_path(); if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { @@ -2036,10 +1978,11 @@ impl Context { url.push_str("/"); } url.push_str(&item_path(ty, names.last().unwrap())); - layout::redirect(writer, &url)?; + layout::redirect(&url) + } else { + String::new() } } - Ok(()) } /// Non-parallelized version of rendering an item. This will take the input @@ -2075,13 +2018,12 @@ impl Context { info!("Recursing into {}", self.dst.display()); - let mut buf = Vec::new(); - self.render_item(&mut buf, &item, false).unwrap(); + let buf = self.render_item(&item, false); // buf will be empty if the module is stripped and there is no redirect for it if !buf.is_empty() { self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join("index.html"); - scx.fs.write(&joint_dst, buf)?; + scx.fs.write(&joint_dst, buf.as_bytes())?; } let m = match item.inner { @@ -2094,9 +2036,7 @@ impl Context { if !self.render_redirect_pages { let items = self.build_sidebar_items(&m); let js_dst = self.dst.join("sidebar-items.js"); - let mut v = Vec::new(); - try_err!(write!(&mut v, "initSidebarItems({});", - as_json(&items)), &js_dst); + let v = format!("initSidebarItems({});", as_json(&items)); scx.fs.write(&js_dst, &v)?; } @@ -2110,8 +2050,7 @@ impl Context { self.dst = prev; self.current.pop().unwrap(); } else if item.name.is_some() { - let mut buf = Vec::new(); - self.render_item(&mut buf, &item, true).unwrap(); + let buf = self.render_item(&item, true); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { let name = item.name.as_ref().unwrap(); @@ -2119,7 +2058,7 @@ impl Context { let file_name = &item_path(item_type, name); self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(file_name); - self.shared.fs.write(&joint_dst, buf)?; + self.shared.fs.write(&joint_dst, buf.as_bytes())?; if !self.render_redirect_pages { all.append(full_path(self, &item), &item_type); @@ -2129,18 +2068,16 @@ impl Context { // URL for the page. let redir_name = format!("{}.{}.html", name, item_type.name_space()); let redir_dst = self.dst.join(redir_name); - let mut v = Vec::new(); - try_err!(layout::redirect(&mut v, file_name), &redir_dst); - self.shared.fs.write(&redir_dst, &v)?; + let v = layout::redirect(file_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; } // If the item is a macro, redirect from the old macro URL (with !) // to the new one (without). if item_type == ItemType::Macro { let redir_name = format!("{}.{}!.html", item_type, name); let redir_dst = self.dst.join(redir_name); - let mut v = Vec::new(); - try_err!(layout::redirect(&mut v, file_name), &redir_dst); - self.shared.fs.write(&redir_dst, &v)?; + let v = layout::redirect(file_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; } } } @@ -2172,7 +2109,7 @@ impl Context { } } -impl<'a> Item<'a> { +impl Context { /// Generates a url appropriate for an `href` attribute back to the source of /// this item. /// @@ -2182,26 +2119,26 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn src_href(&self) -> Option { - let mut root = self.cx.root_path(); + fn src_href(&self, item: &clean::Item) -> Option { + let mut root = self.root_path(); let cache = cache(); let mut path = String::new(); // We can safely ignore macros from other libraries - let file = match self.item.source.filename { + let file = match item.source.filename { FileName::Real(ref path) => path, _ => return None, }; - let (krate, path) = if self.item.def_id.is_local() { - if let Some(path) = self.cx.shared.local_sources.get(file) { - (&self.cx.shared.layout.krate, path) + let (krate, path) = if item.def_id.is_local() { + if let Some(path) = self.shared.local_sources.get(file) { + (&self.shared.layout.krate, path) } else { return None; } } else { - let (krate, src_root) = match *cache.extern_locations.get(&self.item.def_id.krate)? { + let (krate, src_root) = match *cache.extern_locations.get(&item.def_id.krate)? { (ref name, ref src, Local) => (name, src), (ref name, ref src, Remote(ref s)) => { root = s.to_string(); @@ -2221,10 +2158,10 @@ impl<'a> Item<'a> { (krate, &path) }; - let lines = if self.item.source.loline == self.item.source.hiline { - self.item.source.loline.to_string() + let lines = if item.source.loline == item.source.hiline { + item.source.loline.to_string() } else { - format!("{}-{}", self.item.source.loline, self.item.source.hiline) + format!("{}-{}", item.source.loline, item.source.hiline) }; Some(format!("{root}src/{krate}/{path}#{lines}", root = Escape(&root), @@ -2234,114 +2171,113 @@ impl<'a> Item<'a> { } } -fn wrap_into_docblock(w: &mut fmt::Formatter<'_>, - f: F) -> fmt::Result -where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result { - write!(w, "
")?; - f(w)?; +fn wrap_into_docblock(w: &mut Buffer, f: F) + where F: FnOnce(&mut Buffer) +{ + write!(w, "
"); + f(w); write!(w, "
") } -impl<'a> fmt::Display for Item<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - debug_assert!(!self.item.is_stripped()); - // Write the breadcrumb trail header for the top - write!(fmt, "

")?; - if let Some(version) = self.item.stable_since() { - write!(fmt, "{0}", - version)?; - } - write!(fmt, - "\ - \ - []\ - \ - ")?; - - // Write `src` tag - // - // When this item is part of a `pub use` in a downstream crate, the - // [src] link in the downstream documentation will actually come back to - // this page, and this link will be auto-clicked. The `id` attribute is - // used to find the link to auto-click. - if self.cx.shared.include_sources && !self.item.is_primitive() { - if let Some(l) = self.src_href() { - write!(fmt, "[src]", - l, "goto source code")?; - } - } - - write!(fmt, "")?; // out-of-band - write!(fmt, "")?; - match self.item.inner { - clean::ModuleItem(ref m) => if m.is_crate { - write!(fmt, "Crate ")?; - } else { - write!(fmt, "Module ")?; - }, - clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => write!(fmt, "Function ")?, - clean::TraitItem(..) => write!(fmt, "Trait ")?, - clean::StructItem(..) => write!(fmt, "Struct ")?, - clean::UnionItem(..) => write!(fmt, "Union ")?, - clean::EnumItem(..) => write!(fmt, "Enum ")?, - clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, - clean::MacroItem(..) => write!(fmt, "Macro ")?, - clean::ProcMacroItem(ref mac) => match mac.kind { - MacroKind::Bang => write!(fmt, "Macro ")?, - MacroKind::Attr => write!(fmt, "Attribute Macro ")?, - MacroKind::Derive => write!(fmt, "Derive Macro ")?, - } - clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, - clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?, - clean::ConstantItem(..) => write!(fmt, "Constant ")?, - clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?, - clean::KeywordItem(..) => write!(fmt, "Keyword ")?, - clean::OpaqueTyItem(..) => write!(fmt, "Opaque Type ")?, - clean::TraitAliasItem(..) => write!(fmt, "Trait Alias ")?, - _ => { - // We don't generate pages for any other type. - unreachable!(); - } +fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) { + debug_assert!(!item.is_stripped()); + // Write the breadcrumb trail header for the top + write!(buf, "

"); + if let Some(version) = item.stable_since() { + write!(buf, "{0}", + version); + } + write!(buf, + "\ + \ + []\ + \ + "); + + // Write `src` tag + // + // When this item is part of a `pub use` in a downstream crate, the + // [src] link in the downstream documentation will actually come back to + // this page, and this link will be auto-clicked. The `id` attribute is + // used to find the link to auto-click. + if cx.shared.include_sources && !item.is_primitive() { + if let Some(l) = cx.src_href(item) { + write!(buf, "[src]", + l, "goto source code"); + } + } + + write!(buf, ""); // out-of-band + write!(buf, ""); + let name = match item.inner { + clean::ModuleItem(ref m) => if m.is_crate { + "Crate " + } else { + "Module " + }, + clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ", + clean::TraitItem(..) => "Trait ", + clean::StructItem(..) => "Struct ", + clean::UnionItem(..) => "Union ", + clean::EnumItem(..) => "Enum ", + clean::TypedefItem(..) => "Type Definition ", + clean::MacroItem(..) => "Macro ", + clean::ProcMacroItem(ref mac) => match mac.kind { + MacroKind::Bang => "Macro ", + MacroKind::Attr => "Attribute Macro ", + MacroKind::Derive => "Derive Macro ", + } + clean::PrimitiveItem(..) => "Primitive Type ", + clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", + clean::ConstantItem(..) => "Constant ", + clean::ForeignTypeItem => "Foreign Type ", + clean::KeywordItem(..) => "Keyword ", + clean::OpaqueTyItem(..) => "Opaque Type ", + clean::TraitAliasItem(..) => "Trait Alias ", + _ => { + // We don't generate pages for any other type. + unreachable!(); } - if !self.item.is_primitive() && !self.item.is_keyword() { - let cur = &self.cx.current; - let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() }; - for (i, component) in cur.iter().enumerate().take(amt) { - write!(fmt, "{}::", - "../".repeat(cur.len() - i - 1), - component)?; - } + }; + buf.write_str(name); + if !item.is_primitive() && !item.is_keyword() { + let cur = &cx.current; + let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; + for (i, component) in cur.iter().enumerate().take(amt) { + write!(buf, "{}::", + "../".repeat(cur.len() - i - 1), + component); } - write!(fmt, "{}", - self.item.type_(), self.item.name.as_ref().unwrap())?; - - write!(fmt, "

")?; // in-band - - match self.item.inner { - clean::ModuleItem(ref m) => - item_module(fmt, self.cx, self.item, &m.items), - clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => - item_function(fmt, self.cx, self.item, f), - clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t), - clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s), - clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s), - clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e), - clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t), - clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m), - clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m), - clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p), - clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => - item_static(fmt, self.cx, self.item, i), - clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c), - clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item), - clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k), - clean::OpaqueTyItem(ref e, _) => item_opaque_ty(fmt, self.cx, self.item, e), - clean::TraitAliasItem(ref ta) => item_trait_alias(fmt, self.cx, self.item, ta), - _ => { - // We don't generate pages for any other type. - unreachable!(); - } + } + write!(buf, "{}", + item.type_(), item.name.as_ref().unwrap()); + + write!(buf, "

"); // in-band + + match item.inner { + clean::ModuleItem(ref m) => + item_module(buf, cx, item, &m.items), + clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => + item_function(buf, cx, item, f), + clean::TraitItem(ref t) => item_trait(buf, cx, item, t), + clean::StructItem(ref s) => item_struct(buf, cx, item, s), + clean::UnionItem(ref s) => item_union(buf, cx, item, s), + clean::EnumItem(ref e) => item_enum(buf, cx, item, e), + clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t), + clean::MacroItem(ref m) => item_macro(buf, cx, item, m), + clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), + clean::PrimitiveItem(ref p) => item_primitive(buf, cx, item, p), + clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => + item_static(buf, cx, item, i), + clean::ConstantItem(ref c) => item_constant(buf, cx, item, c), + clean::ForeignTypeItem => item_foreign_type(buf, cx, item), + clean::KeywordItem(ref k) => item_keyword(buf, cx, item, k), + clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e), + clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta), + _ => { + // We don't generate pages for any other type. + unreachable!(); } } } @@ -2395,24 +2331,23 @@ fn shorten(s: String) -> String { } } -fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt::Result { +fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false)?; - document_full(w, item, cx, "", false)?; - Ok(()) + document_stability(w, cx, item, false); + document_full(w, item, cx, "", false); } /// Render md_text as markdown. fn render_markdown( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, md_text: &str, links: Vec<(String, String)>, prefix: &str, is_hidden: bool, -) -> fmt::Result { +) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}{}
", if is_hidden { " hidden" } else { "" }, @@ -2422,13 +2357,13 @@ fn render_markdown( } fn document_short( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, prefix: &str, is_hidden: bool, -) -> fmt::Result { +) { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { format!("{} [Read more]({})", @@ -2436,46 +2371,41 @@ fn document_short( } else { plain_summary_line(Some(s)) }; - render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?; + render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden); } else if !prefix.is_empty() { write!(w, "
{}
", if is_hidden { " hidden" } else { "" }, - prefix)?; + prefix); } - Ok(()) } -fn document_full(w: &mut fmt::Formatter<'_>, item: &clean::Item, - cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result { +fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, is_hidden: bool) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); - render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?; + render_markdown(w, cx, &*s, item.links(), prefix, is_hidden); } else if !prefix.is_empty() { write!(w, "
{}
", if is_hidden { " hidden" } else { "" }, - prefix)?; + prefix); } - Ok(()) } -fn document_stability(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item, - is_hidden: bool) -> fmt::Result { +fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) { let stabilities = short_stability(item, cx); if !stabilities.is_empty() { - write!(w, "
", if is_hidden { " hidden" } else { "" })?; + write!(w, "
", if is_hidden { " hidden" } else { "" }); for stability in stabilities { - write!(w, "{}", stability)?; + write!(w, "{}", stability); } - write!(w, "
")?; + write!(w, "
"); } - Ok(()) } fn document_non_exhaustive_header(item: &clean::Item) -> &str { if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" } } -fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result { +fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { write!(w, "
", { if item.is_struct() { @@ -2487,31 +2417,29 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm } else { "type" } - })?; + }); if item.is_struct() { write!(w, "Non-exhaustive structs could have additional fields added in future. \ Therefore, non-exhaustive structs cannot be constructed in external crates \ using the traditional Struct {{ .. }} syntax; cannot be \ matched against without a wildcard ..; and \ - struct update syntax will not work.")?; + struct update syntax will not work."); } else if item.is_enum() { write!(w, "Non-exhaustive enums could have additional variants added in future. \ Therefore, when matching against variants of non-exhaustive enums, an \ - extra wildcard arm must be added to account for any future variants.")?; + extra wildcard arm must be added to account for any future variants."); } else if item.is_variant() { write!(w, "Non-exhaustive enum variants could have additional fields added in future. \ Therefore, non-exhaustive enum variants cannot be constructed in external \ - crates and cannot be matched against.")?; + crates and cannot be matched against."); } else { write!(w, "This type will require a wildcard arm in any match statements or \ - constructors.")?; + constructors."); } - write!(w, "
")?; + write!(w, "
"); } - - Ok(()) } fn name_key(name: &str) -> (&str, u64, usize) { @@ -2535,9 +2463,8 @@ fn name_key(name: &str) -> (&str, u64, usize) { } } -fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, - item: &clean::Item, items: &[clean::Item]) -> fmt::Result { - document(w, cx, item)?; +fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { + document(w, cx, item); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -2628,13 +2555,13 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, curty = myty; } else if myty != curty { if curty.is_some() { - write!(w, "")?; + write!(w, ""); } curty = myty; let (short, name) = item_ty_to_strs(&myty.unwrap()); write!(w, "

\ {name}

\n", - id = cx.derive_id(short.to_owned()), name = name)?; + id = cx.derive_id(short.to_owned()), name = name); } match myitem.inner { @@ -2646,20 +2573,20 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, write!(w, "")?; + write!(w, ""); } clean::ImportItem(ref import) => { write!(w, "", - VisSpace(&myitem.visibility), *import)?; + VisSpace(&myitem.visibility), *import); } _ => { @@ -2704,15 +2631,14 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, }) .collect::>() .join(" "), - )?; + ); } } } if curty.is_some() { - write!(w, "
{}extern crate {} as {};", VisSpace(&myitem.visibility), anchor(myitem.def_id, src), - name)? + name) } None => { write!(w, "
{}extern crate {};", VisSpace(&myitem.visibility), - anchor(myitem.def_id, name))? + anchor(myitem.def_id, name)) } } - write!(w, "
{}{}
")?; + write!(w, ""); } - Ok(()) } /// Render the stability and deprecation tags that are displayed in the item's summary at the @@ -2861,33 +2787,30 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { stability } -fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - c: &clean::Constant) -> fmt::Result { - write!(w, "
")?;
-    render_attributes(w, it, false)?;
+fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) {
+    write!(w, "
");
+    render_attributes(w, it, false);
     write!(w, "{vis}const \
                {name}: {typ}
", vis = VisSpace(&it.visibility), name = it.name.as_ref().unwrap(), - typ = c.type_)?; + typ = c.type_); document(w, cx, it) } -fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - s: &clean::Static) -> fmt::Result { - write!(w, "
")?;
-    render_attributes(w, it, false)?;
+fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) {
+    write!(w, "
");
+    render_attributes(w, it, false);
     write!(w, "{vis}static {mutability}\
                {name}: {typ}
", vis = VisSpace(&it.visibility), mutability = MutableSpace(s.mutability), name = it.name.as_ref().unwrap(), - typ = s.type_)?; + typ = s.type_); document(w, cx, it) } -fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - f: &clean::Function) -> fmt::Result { +fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), @@ -2898,8 +2821,8 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, it.name.as_ref().unwrap(), f.generics ).len(); - write!(w, "{}
", render_spotlight_traits(it)?)?;
-    render_attributes(w, it, false)?;
+    write!(w, "{}
", render_spotlight_traits(it));
+    render_attributes(w, it, false);
     write!(w,
            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
            {name}{generics}{decl}{where_clause}
", @@ -2916,12 +2839,12 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, header_len, indent: 0, asyncness: f.header.asyncness, - })?; + }); document(w, cx, it) } -fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<'_>, - implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result { +fn render_implementor(cx: &Context, implementor: &Impl, w: &mut Buffer, + implementor_dups: &FxHashMap<&str, (DefId, bool)>) { // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { @@ -2933,20 +2856,18 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<' _ => false, }; render_impl(w, cx, implementor, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since(), false, Some(use_absolute), false, false)?; - Ok(()) + implementor.impl_item.stable_since(), false, Some(use_absolute), false, false); } -fn render_impls(cx: &Context, w: &mut fmt::Formatter<'_>, +fn render_impls(cx: &Context, w: &mut Buffer, traits: &[&&Impl], - containing_item: &clean::Item) -> fmt::Result { + containing_item: &clean::Item) { for i in traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); render_impl(w, cx, i, assoc_link, - RenderMode::Normal, containing_item.stable_since(), true, None, false, true)?; + RenderMode::Normal, containing_item.stable_since(), true, None, false, true); } - Ok(()) } fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String { @@ -2974,11 +2895,11 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering { } fn item_trait( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, -) -> fmt::Result { +) { let bounds = bounds(&t.bounds, false); let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); @@ -2987,146 +2908,144 @@ fn item_trait( // Output the trait definition wrap_into_docblock(w, |w| { - write!(w, "
")?;
-        render_attributes(w, it, true)?;
+        write!(w, "
");
+        render_attributes(w, it, true);
         write!(w, "{}{}{}trait {}{}{}",
                VisSpace(&it.visibility),
                UnsafetySpace(t.unsafety),
                if t.is_auto { "auto " } else { "" },
                it.name.as_ref().unwrap(),
                t.generics,
-               bounds)?;
+               bounds);
 
         if !t.generics.where_predicates.is_empty() {
-            write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
+            write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true });
         } else {
-            write!(w, " ")?;
+            write!(w, " ");
         }
 
         if t.items.is_empty() {
-            write!(w, "{{ }}")?;
+            write!(w, "{{ }}");
         } else {
             // FIXME: we should be using a derived_id for the Anchors here
-            write!(w, "{{\n")?;
+            write!(w, "{{\n");
             for t in &types {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
-                write!(w, ";\n")?;
+                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+                write!(w, ";\n");
             }
             if !types.is_empty() && !consts.is_empty() {
-                w.write_str("\n")?;
+                w.write_str("\n");
             }
             for t in &consts {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
-                write!(w, ";\n")?;
+                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+                write!(w, ";\n");
             }
             if !consts.is_empty() && !required.is_empty() {
-                w.write_str("\n")?;
+                w.write_str("\n");
             }
             for (pos, m) in required.iter().enumerate() {
-                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
-                write!(w, ";\n")?;
+                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
+                write!(w, ";\n");
 
                 if pos < required.len() - 1 {
-                   write!(w, "
")?; + write!(w, "
"); } } if !required.is_empty() && !provided.is_empty() { - w.write_str("\n")?; + w.write_str("\n"); } for (pos, m) in provided.iter().enumerate() { - render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); match m.inner { clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { - write!(w, ",\n {{ ... }}\n")?; + write!(w, ",\n {{ ... }}\n"); }, _ => { - write!(w, " {{ ... }}\n")?; + write!(w, " {{ ... }}\n"); }, } if pos < provided.len() - 1 { - write!(w, "
")?; + write!(w, "
"); } } - write!(w, "}}")?; + write!(w, "}}"); } write!(w, "
") - })?; + }); // Trait documentation - document(w, cx, it)?; + document(w, cx, it); fn write_small_section_header( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, id: &str, title: &str, extra_content: &str, - ) -> fmt::Result { + ) { write!(w, "

\ {1}\

{2}", id, title, extra_content) } - fn write_loading_content(w: &mut fmt::Formatter<'_>, extra_content: &str) -> fmt::Result { + fn write_loading_content(w: &mut Buffer, extra_content: &str) { write!(w, "{}Loading content...", extra_content) } - fn trait_item(w: &mut fmt::Formatter<'_>, cx: &Context, m: &clean::Item, t: &clean::Item) - -> fmt::Result { + fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { let name = m.name.as_ref().unwrap(); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

{extra}", - extra = render_spotlight_traits(m)?, + extra = render_spotlight_traits(m), id = id, - ns_id = ns_id)?; - render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?; - write!(w, "")?; - render_stability_since(w, m, t)?; - write!(w, "

")?; - document(w, cx, m)?; - Ok(()) + ns_id = ns_id); + render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); + write!(w, ""); + render_stability_since(w, m, t); + write!(w, ""); + document(w, cx, m); } if !types.is_empty() { write_small_section_header(w, "associated-types", "Associated Types", - "
")?; + "
"); for t in &types { - trait_item(w, cx, *t, it)?; + trait_item(w, cx, *t, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } if !consts.is_empty() { write_small_section_header(w, "associated-const", "Associated Constants", - "
")?; + "
"); for t in &consts { - trait_item(w, cx, *t, it)?; + trait_item(w, cx, *t, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } // Output the documentation for each function individually if !required.is_empty() { write_small_section_header(w, "required-methods", "Required methods", - "
")?; + "
"); for m in &required { - trait_item(w, cx, *m, it)?; + trait_item(w, cx, *m, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } if !provided.is_empty() { write_small_section_header(w, "provided-methods", "Provided methods", - "
")?; + "
"); for m in &provided { - trait_item(w, cx, *m, it)?; + trait_item(w, cx, *m, it); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } // If there are methods directly on this trait object, render them here. - render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?; + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All); let cache = cache(); @@ -3165,7 +3084,7 @@ fn item_trait( concrete.sort_by(compare_impl); if !foreign.is_empty() { - write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "")?; + write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { let assoc_link = AssocItemLink::GotoSource( @@ -3174,44 +3093,44 @@ fn item_trait( ); render_impl(w, cx, &implementor, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since(), false, - None, true, false)?; + None, true, false); } - write_loading_content(w, "")?; + write_loading_content(w, ""); } write_small_section_header(w, "implementors", "Implementors", - "
")?; + "
"); for implementor in concrete { - render_implementor(cx, implementor, w, &implementor_dups)?; + render_implementor(cx, implementor, w, &implementor_dups); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); if t.auto { write_small_section_header(w, "synthetic-implementors", "Auto implementors", - "
")?; + "
"); for implementor in synthetic { synthetic_types.extend( collect_paths_for_type(implementor.inner_impl().for_.clone()) ); - render_implementor(cx, implementor, w, &implementor_dups)?; + render_implementor(cx, implementor, w, &implementor_dups); } - write_loading_content(w, "
")?; + write_loading_content(w, "
"); } } else { // even without any implementations to write in, we still want the heading and list, so the // implementors javascript file pulled in below has somewhere to write the impls into write_small_section_header(w, "implementors", "Implementors", - "
")?; - write_loading_content(w, "
")?; + "
"); + write_loading_content(w, "
"); if t.auto { write_small_section_header(w, "synthetic-implementors", "Auto implementors", - "
")?; - write_loading_content(w, "
")?; + "
"); + write_loading_content(w, "
"); } } write!(w, r#""#, - as_json(&synthetic_types))?; + as_json(&synthetic_types)); write!(w, r#"", - name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), - ty = it.type_().css_class(), - path = relpath)?; - if parentlen == 0 { - // There is no sidebar-items.js beyond the crate root path - // FIXME maybe dynamic crate loading can be merged here - } else { - write!(fmt, "", - path = relpath)?; - } - // Closes sidebar-elems div. - write!(fmt, "")?; - - Ok(()) + _ => "", + }, + it.name.as_ref().unwrap()); + } + + if it.is_crate() { + if let Some(ref version) = cache().crate_version { + write!(buffer, + "
\ +

Version {}

\ +
", + version); + } + } + + write!(buffer, "
"); + if it.is_crate() { + write!(buffer, "

See all {}'s items

", + it.name.as_ref().expect("crates always have a name")); + } + match it.inner { + clean::StructItem(ref s) => sidebar_struct(buffer, it, s), + clean::TraitItem(ref t) => sidebar_trait(buffer, it, t), + clean::PrimitiveItem(ref p) => sidebar_primitive(buffer, it, p), + clean::UnionItem(ref u) => sidebar_union(buffer, it, u), + clean::EnumItem(ref e) => sidebar_enum(buffer, it, e), + clean::TypedefItem(ref t, _) => sidebar_typedef(buffer, it, t), + clean::ModuleItem(ref m) => sidebar_module(buffer, it, &m.items), + clean::ForeignTypeItem => sidebar_foreign_type(buffer, it), + _ => (), + } + + // The sidebar is designed to display sibling functions, modules and + // other miscellaneous information. since there are lots of sibling + // items (and that causes quadratic growth in large modules), + // we refactor common parts into a shared JavaScript file per module. + // still, we don't move everything into JS because we want to preserve + // as much HTML as possible in order to allow non-JS-enabled browsers + // to navigate the documentation (though slightly inefficiently). + + write!(buffer, "

"); + for (i, name) in cx.current.iter().take(parentlen).enumerate() { + if i > 0 { + write!(buffer, "::"); + } + write!(buffer, "{}", + &cx.root_path()[..(cx.current.len() - i - 1) * 3], + *name); + } + write!(buffer, "

"); + + // Sidebar refers to the enclosing module, not this module. + let relpath = if it.is_mod() { "../" } else { "" }; + write!(buffer, + "", + name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), + ty = it.type_().css_class(), + path = relpath); + if parentlen == 0 { + // There is no sidebar-items.js beyond the crate root path + // FIXME maybe dynamic crate loading can be merged here + } else { + write!(buffer, "", + path = relpath); } + // Closes sidebar-elems div. + write!(buffer, "
"); } fn get_next_url(used_links: &mut FxHashSet, url: String) -> String { @@ -4570,8 +4452,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { out } -fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - s: &clean::Struct) -> fmt::Result { +fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) { let mut sidebar = String::new(); let fields = get_struct_fields_name(&s.fields); @@ -4585,9 +4466,8 @@ fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String { @@ -4611,8 +4491,7 @@ fn is_negative_impl(i: &clean::Impl) -> bool { i.polarity == Some(clean::ImplPolarity::Negative) } -fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - t: &clean::Trait) -> fmt::Result { +fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { let mut sidebar = String::new(); let types = t.items @@ -4720,27 +4599,23 @@ fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); - write!(fmt, "
{}
", sidebar) + write!(buf, "
{}
", sidebar) } -fn sidebar_primitive(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - _p: &clean::PrimitiveType) -> fmt::Result { +fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item, _p: &clean::PrimitiveType) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } -fn sidebar_typedef(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - _t: &clean::Typedef) -> fmt::Result { +fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item, _t: &clean::Typedef) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } fn get_struct_fields_name(fields: &[clean::Item]) -> String { @@ -4758,8 +4633,7 @@ fn get_struct_fields_name(fields: &[clean::Item]) -> String { .collect() } -fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - u: &clean::Union) -> fmt::Result { +fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) { let mut sidebar = String::new(); let fields = get_struct_fields_name(&u.fields); @@ -4771,13 +4645,11 @@ fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } -fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - e: &clean::Enum) -> fmt::Result { +fn sidebar_enum(buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) { let mut sidebar = String::new(); let variants = e.variants.iter() @@ -4795,9 +4667,8 @@ fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { @@ -4831,8 +4702,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { } } -fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, - items: &[clean::Item]) -> fmt::Result { +fn sidebar_module(buf: &mut Buffer, _it: &clean::Item, items: &[clean::Item]) { let mut sidebar = String::new(); if items.iter().any(|it| it.type_() == ItemType::ExternCrate || @@ -4859,72 +4729,67 @@ fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, } if !sidebar.is_empty() { - write!(fmt, "
    {}
", sidebar)?; + write!(buf, "
    {}
", sidebar); } - Ok(()) } -fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Result { +fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "
{}
", sidebar)?; + write!(buf, "
{}
", sidebar); } - Ok(()) } -fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - t: &clean::Macro) -> fmt::Result { +fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), None, None)) - })?; + }); document(w, cx, it) } -fn item_proc_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) - -> fmt::Result -{ +fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) { let name = it.name.as_ref().expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - write!(w, "
")?;
-            write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
-            write!(w, "
")?; + write!(w, "
");
+            write!(w, "{}!() {{ /* proc-macro */ }}", name);
+            write!(w, "
"); } MacroKind::Attr => { - write!(w, "
")?;
-            write!(w, "#[{}]", name)?;
-            write!(w, "
")?; + write!(w, "
");
+            write!(w, "#[{}]", name);
+            write!(w, "
"); } MacroKind::Derive => { - write!(w, "
")?;
-            write!(w, "#[derive({})]", name)?;
+            write!(w, "
");
+            write!(w, "#[derive({})]", name);
             if !m.helpers.is_empty() {
-                writeln!(w, "\n{{")?;
-                writeln!(w, "    // Attributes available to this derive:")?;
+                writeln!(w, "\n{{");
+                writeln!(w, "    // Attributes available to this derive:");
                 for attr in &m.helpers {
-                    writeln!(w, "    #[{}]", attr)?;
+                    writeln!(w, "    #[{}]", attr);
                 }
-                write!(w, "}}")?;
+                write!(w, "}}");
             }
-            write!(w, "
")?; + write!(w, "
"); } } document(w, cx, it) } -fn item_primitive(w: &mut fmt::Formatter<'_>, cx: &Context, +fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, - _p: &clean::PrimitiveType) -> fmt::Result { - document(w, cx, it)?; + _p: &clean::PrimitiveType) { + document(w, cx, it); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context, +fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item, - _p: &str) -> fmt::Result { + _p: &str) { document(w, cx, it) } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index c1f1f59d9149a..d840683a7af87 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -4,10 +4,10 @@ use crate::fold::DocFolder; use crate::html::layout; use crate::html::render::{Error, SharedContext, BASIC_KEYWORDS}; use crate::html::highlight; +use crate::html::format::Buffer; use std::ffi::OsStr; use std::fs; use std::path::{Component, Path, PathBuf}; -use std::fmt; use syntax::source_map::FileName; crate fn render(dst: &Path, scx: &mut SharedContext, @@ -105,7 +105,6 @@ impl<'a> SourceCollector<'a> { cur.push(&fname); href.push_str(&fname.to_string_lossy()); - let mut v = Vec::new(); 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); @@ -120,15 +119,10 @@ impl<'a> SourceCollector<'a> { extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], }; - let result = layout::render(&mut v, &self.scx.layout, - &page, &(""), &Source(contents), - self.scx.css_file_extension.is_some(), - &self.scx.themes, - self.scx.generate_search_filter); - if let Err(e) = result { - return Err(Error::new(e, &cur)); - } - self.scx.fs.write(&cur, &v)?; + let v = layout::render(&self.scx.layout, + &page, "", |buf: &mut _| print_src(buf, &contents), + &self.scx.themes); + self.scx.fs.write(&cur, v.as_bytes())?; self.scx.local_sources.insert(p.clone(), href); Ok(()) } @@ -163,25 +157,19 @@ where /// Wrapper struct to render the source code of a file. This will do things like /// adding line numbers to the left-hand side. -struct Source<'a>(&'a str); - -impl<'a> fmt::Display for Source<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Source(s) = *self; - let lines = s.lines().count(); - let mut cols = 0; - let mut tmp = lines; - while tmp > 0 { - cols += 1; - tmp /= 10; - } - write!(fmt, "
")?;
-        for i in 1..=lines {
-            write!(fmt, "{0:1$}\n", i, cols)?;
-        }
-        write!(fmt, "
")?; - write!(fmt, "{}", - highlight::render_with_highlighting(s, None, None, None))?; - Ok(()) +fn print_src(buf: &mut Buffer, s: &str) { + let lines = s.lines().count(); + let mut cols = 0; + let mut tmp = lines; + while tmp > 0 { + cols += 1; + tmp /= 10; + } + write!(buf, "
");
+    for i in 1..=lines {
+        write!(buf, "{0:1$}\n", i, cols);
     }
+    write!(buf, "
"); + write!(buf, "{}", + highlight::render_with_highlighting(s, None, None, None)); } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 637c6ef8e8e0b..309e5575ee403 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -344,7 +344,7 @@ if (!DOMTokenList.prototype.remove) { var set_fragment = function(name) { if (browserSupportsHistoryApi()) { history.replaceState(null, null, "#" + name); - window.hashchange(); + highlightSourceLines(null); } else { location.replace("#" + name); } diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 40a6a156972f6..eae998ca3ecbf 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -119,7 +119,7 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { function getSystemValue() { var property = getComputedStyle(document.documentElement).getPropertyValue('content'); - return property.replace(/\"\'/g, ""); + return property.replace(/[\"\']/g, ""); } switchTheme(currentTheme, mainTheme, diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs index a5f685a159b39..ecbcc2a4b496f 100644 --- a/src/test/ui/consts/const-err2.rs +++ b/src/test/ui/consts/const-err2.rs @@ -5,6 +5,7 @@ #![feature(rustc_attrs)] #![allow(exceeding_bitshifts)] + #![deny(const_err)] fn black_box(_: T) { @@ -21,7 +22,7 @@ fn main() { let d = 42u8 - (42u8 + 1); //~^ ERROR const_err let _e = [5u8][1]; - //~^ ERROR const_err + //~^ ERROR index out of bounds black_box(a); black_box(b); black_box(c); diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr index 659c3afc618a9..1d84d44dc27b3 100644 --- a/src/test/ui/consts/const-err2.stderr +++ b/src/test/ui/consts/const-err2.stderr @@ -1,35 +1,35 @@ error: this expression will panic at runtime - --> $DIR/const-err2.rs:15:13 + --> $DIR/const-err2.rs:16:13 | LL | let a = -std::i8::MIN; | ^^^^^^^^^^^^^ attempt to negate with overflow | note: lint level defined here - --> $DIR/const-err2.rs:8:9 + --> $DIR/const-err2.rs:9:9 | LL | #![deny(const_err)] | ^^^^^^^^^ error: this expression will panic at runtime - --> $DIR/const-err2.rs:17:13 + --> $DIR/const-err2.rs:18:13 | LL | let b = 200u8 + 200u8 + 200u8; | ^^^^^^^^^^^^^ attempt to add with overflow error: this expression will panic at runtime - --> $DIR/const-err2.rs:19:13 + --> $DIR/const-err2.rs:20:13 | LL | let c = 200u8 * 4; | ^^^^^^^^^ attempt to multiply with overflow error: this expression will panic at runtime - --> $DIR/const-err2.rs:21:13 + --> $DIR/const-err2.rs:22:13 | LL | let d = 42u8 - (42u8 + 1); | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/const-err2.rs:23:14 + --> $DIR/const-err2.rs:24:14 | LL | let _e = [5u8][1]; | ^^^^^^^^ diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs new file mode 100644 index 0000000000000..a9cf04cda7a5a --- /dev/null +++ b/src/test/ui/consts/const-err3.rs @@ -0,0 +1,30 @@ +// needed because negating int::MIN will behave differently between +// optimized compilation and unoptimized compilation and thus would +// lead to different lints being emitted +// compile-flags: -C overflow-checks=on -O + +#![feature(rustc_attrs)] +#![allow(exceeding_bitshifts)] + +#![deny(const_err)] + +fn black_box(_: T) { + unimplemented!() +} + +fn main() { + let a = -std::i8::MIN; + //~^ ERROR const_err + let b = 200u8 + 200u8 + 200u8; + //~^ ERROR const_err + let c = 200u8 * 4; + //~^ ERROR const_err + let d = 42u8 - (42u8 + 1); + //~^ ERROR const_err + let _e = [5u8][1]; + //~^ ERROR const_err + black_box(a); + black_box(b); + black_box(c); + black_box(d); +} diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr new file mode 100644 index 0000000000000..0602707be7040 --- /dev/null +++ b/src/test/ui/consts/const-err3.stderr @@ -0,0 +1,38 @@ +error: attempt to negate with overflow + --> $DIR/const-err3.rs:16:13 + | +LL | let a = -std::i8::MIN; + | ^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/const-err3.rs:9:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + +error: attempt to add with overflow + --> $DIR/const-err3.rs:18:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ + +error: attempt to multiply with overflow + --> $DIR/const-err3.rs:20:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ + +error: attempt to subtract with overflow + --> $DIR/const-err3.rs:22:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ + +error: index out of bounds: the len is 1 but the index is 1 + --> $DIR/const-err3.rs:24:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index cd989731452b3..45941398f4b66 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -5,7 +5,7 @@ fn main() { println!("{}", 0u32 - 1); let _x = 0u32 - 1; - //~^ ERROR this expression will panic at runtime [const_err] + //~^ ERROR const_err println!("{}", 1/(1-1)); //~^ ERROR attempt to divide by zero [const_err] //~| ERROR reaching this expression at runtime will panic or abort [const_err] diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs new file mode 100644 index 0000000000000..7adb394144bdd --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors2.rs @@ -0,0 +1,22 @@ +// compile-flags: -C overflow-checks=on -O + +#![deny(const_err)] + +fn main() { + println!("{}", 0u32 - 1); + //~^ ERROR attempt to subtract with overflow + let _x = 0u32 - 1; + //~^ ERROR attempt to subtract with overflow + println!("{}", 1/(1-1)); + //~^ ERROR attempt to divide by zero [const_err] + //~| ERROR reaching this expression at runtime will panic or abort [const_err] + let _x = 1/(1-1); + //~^ ERROR const_err + //~| ERROR const_err + println!("{}", 1/(false as u32)); + //~^ ERROR attempt to divide by zero [const_err] + //~| ERROR reaching this expression at runtime will panic or abort [const_err] + let _x = 1/(false as u32); + //~^ ERROR const_err + //~| ERROR const_err +} diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr new file mode 100644 index 0000000000000..2819e6e8fdbe0 --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr @@ -0,0 +1,68 @@ +error: attempt to subtract with overflow + --> $DIR/promoted_errors2.rs:6:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/promoted_errors2.rs:3:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + +error: attempt to subtract with overflow + --> $DIR/promoted_errors2.rs:8:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:10:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ + +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors2.rs:10:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:13:14 + | +LL | let _x = 1/(1-1); + | ^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/promoted_errors2.rs:13:14 + | +LL | let _x = 1/(1-1); + | ^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:16:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ + +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors2.rs:16:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors2.rs:19:14 + | +LL | let _x = 1/(false as u32); + | ^^^^^^^^^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/promoted_errors2.rs:19:14 + | +LL | let _x = 1/(false as u32); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/consts/issue-64059-2.rs b/src/test/ui/consts/issue-64059-2.rs new file mode 100644 index 0000000000000..38911c3dcf692 --- /dev/null +++ b/src/test/ui/consts/issue-64059-2.rs @@ -0,0 +1,6 @@ +// compile-flags: -C overflow-checks=on -O +// run-pass + +fn main() { + let _ = -(-0.0); +} diff --git a/src/test/ui/consts/issue-64059.rs b/src/test/ui/consts/issue-64059.rs new file mode 100644 index 0000000000000..c4c895fef66cf --- /dev/null +++ b/src/test/ui/consts/issue-64059.rs @@ -0,0 +1,5 @@ +// run-pass + +fn main() { + let _ = -(-0.0); +} diff --git a/src/test/ui/if/if-without-else-as-fn-expr.rs b/src/test/ui/if/if-without-else-as-fn-expr.rs index 15892de83854c..826371be35f45 100644 --- a/src/test/ui/if/if-without-else-as-fn-expr.rs +++ b/src/test/ui/if/if-without-else-as-fn-expr.rs @@ -3,7 +3,6 @@ fn foo(bar: usize) -> usize { return 3; } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } fn foo2(bar: usize) -> usize { @@ -11,7 +10,6 @@ fn foo2(bar: usize) -> usize { return 3; }; //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] x } @@ -20,7 +18,6 @@ fn foo3(bar: usize) -> usize { 3 } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } fn foo_let(bar: usize) -> usize { @@ -28,7 +25,6 @@ fn foo_let(bar: usize) -> usize { return 3; } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } fn foo2_let(bar: usize) -> usize { @@ -36,7 +32,6 @@ fn foo2_let(bar: usize) -> usize { return 3; }; //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] x } @@ -45,7 +40,6 @@ fn foo3_let(bar: usize) -> usize { 3 } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } // FIXME(60254): deduplicate first error in favor of second. diff --git a/src/test/ui/if/if-without-else-as-fn-expr.stderr b/src/test/ui/if/if-without-else-as-fn-expr.stderr index 06600b1cb9aea..b49c2aa6319df 100644 --- a/src/test/ui/if/if-without-else-as-fn-expr.stderr +++ b/src/test/ui/if/if-without-else-as-fn-expr.stderr @@ -1,14 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:2:5 - | -LL | / if bar % 5 == 0 { -LL | | return 3; -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause --> $DIR/if-without-else-as-fn-expr.rs:2:5 | @@ -24,20 +13,8 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:10:20 - | -LL | let x: usize = if bar % 5 == 0 { - | ____________________^ -LL | | return 3; -LL | | }; - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:10:20 + --> $DIR/if-without-else-as-fn-expr.rs:9:20 | LL | let x: usize = if bar % 5 == 0 { | _________-__________^ @@ -52,19 +29,8 @@ LL | | }; = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:19:5 - | -LL | / if bar % 5 == 0 { -LL | | 3 -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:19:5 + --> $DIR/if-without-else-as-fn-expr.rs:17:5 | LL | fn foo3(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -78,19 +44,8 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:27:5 - | -LL | / if let 0 = 1 { -LL | | return 3; -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:27:5 + --> $DIR/if-without-else-as-fn-expr.rs:24:5 | LL | fn foo_let(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -104,20 +59,8 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:35:20 - | -LL | let x: usize = if let 0 = 1 { - | ____________________^ -LL | | return 3; -LL | | }; - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:35:20 + --> $DIR/if-without-else-as-fn-expr.rs:31:20 | LL | let x: usize = if let 0 = 1 { | _________-__________^ @@ -132,19 +75,8 @@ LL | | }; = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:44:5 - | -LL | / if let 0 = 1 { -LL | | 3 -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:44:5 + --> $DIR/if-without-else-as-fn-expr.rs:39:5 | LL | fn foo3_let(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -158,7 +90,6 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error: aborting due to 12 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0308, E0317. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0317`. diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index d980d7cccadd5..002b60f9f258d 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -49,6 +49,14 @@ LL | use foo::Bar; error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope --> $DIR/no-method-suggested-traits.rs:32:43 | +LL | fn method(&self) {} + | ------ + | | + | the method is available for `std::boxed::Box>>` here + | the method is available for `std::pin::Pin>>` here + | the method is available for `std::sync::Arc>>` here + | the method is available for `std::rc::Rc>>` here +... LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); | ^^^^^^ | diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs index bf892a8daa27f..f0f1dc6c28667 100644 --- a/src/test/ui/issues/issue-50577.rs +++ b/src/test/ui/issues/issue-50577.rs @@ -2,6 +2,5 @@ fn main() { enum Foo { Drop = assert_eq!(1, 1) //~^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } } diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/issues/issue-50577.stderr index 413c8c5c80b52..0c3ba2ea4f94d 100644 --- a/src/test/ui/issues/issue-50577.stderr +++ b/src/test/ui/issues/issue-50577.stderr @@ -1,13 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-50577.rs:3:16 - | -LL | Drop = assert_eq!(1, 1) - | ^^^^^^^^^^^^^^^^ expected isize, found () - | - = note: expected type `isize` - found type `()` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - error[E0317]: if may be missing an else clause --> $DIR/issue-50577.rs:3:16 | @@ -23,7 +13,6 @@ LL | Drop = assert_eq!(1, 1) = help: consider adding an `else` block that evaluates to the expected type = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0317. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0317`. diff --git a/src/test/ui/issues/issue-8460-const2.rs b/src/test/ui/issues/issue-8460-const2.rs new file mode 100644 index 0000000000000..c3f53e3298b2b --- /dev/null +++ b/src/test/ui/issues/issue-8460-const2.rs @@ -0,0 +1,59 @@ +// compile-flags: -C overflow-checks=on -O + +#![deny(const_err)] + +use std::{isize, i8, i16, i32, i64}; +use std::thread; + +fn main() { + assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); + //~^ ERROR attempt to divide with overflow + assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); + //~^ ERROR attempt to divide with overflow + assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); + //~^ ERROR attempt to divide with overflow + assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); + //~^ ERROR attempt to divide with overflow + assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); + //~^ ERROR attempt to divide with overflow + assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); + //~^ ERROR attempt to divide by zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); + //~^ ERROR attempt to divide by zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); + //~^ ERROR attempt to divide by zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); + //~^ ERROR attempt to divide by zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); + //~^ ERROR attempt to divide by zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with overflow + assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with overflow + assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with overflow + assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with overflow + assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with overflow + assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR this expression will panic at runtime + assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); + //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR this expression will panic at runtime +} diff --git a/src/test/ui/issues/issue-8460-const2.stderr b/src/test/ui/issues/issue-8460-const2.stderr new file mode 100644 index 0000000000000..b688ec1367794 --- /dev/null +++ b/src/test/ui/issues/issue-8460-const2.stderr @@ -0,0 +1,188 @@ +error: attempt to divide with overflow + --> $DIR/issue-8460-const2.rs:9:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-8460-const2.rs:3:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + +error: attempt to divide with overflow + --> $DIR/issue-8460-const2.rs:11:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^ + +error: attempt to divide with overflow + --> $DIR/issue-8460-const2.rs:13:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ + +error: attempt to divide with overflow + --> $DIR/issue-8460-const2.rs:15:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ + +error: attempt to divide with overflow + --> $DIR/issue-8460-const2.rs:17:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ + +error: attempt to divide by zero + --> $DIR/issue-8460-const2.rs:19:36 + | +LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); + | ^^^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:19:36 + | +LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/issue-8460-const2.rs:22:36 + | +LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); + | ^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:22:36 + | +LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); + | ^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/issue-8460-const2.rs:25:36 + | +LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); + | ^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:25:36 + | +LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/issue-8460-const2.rs:28:36 + | +LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); + | ^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:28:36 + | +LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/issue-8460-const2.rs:31:36 + | +LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); + | ^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:31:36 + | +LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: attempt to calculate the remainder with overflow + --> $DIR/issue-8460-const2.rs:34:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ + +error: attempt to calculate the remainder with overflow + --> $DIR/issue-8460-const2.rs:36:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^ + +error: attempt to calculate the remainder with overflow + --> $DIR/issue-8460-const2.rs:38:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ + +error: attempt to calculate the remainder with overflow + --> $DIR/issue-8460-const2.rs:40:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ + +error: attempt to calculate the remainder with overflow + --> $DIR/issue-8460-const2.rs:42:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ + +error: attempt to calculate the remainder with a divisor of zero + --> $DIR/issue-8460-const2.rs:44:36 + | +LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); + | ^^^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:44:36 + | +LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: attempt to calculate the remainder with a divisor of zero + --> $DIR/issue-8460-const2.rs:47:36 + | +LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); + | ^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:47:36 + | +LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); + | ^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: attempt to calculate the remainder with a divisor of zero + --> $DIR/issue-8460-const2.rs:50:36 + | +LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); + | ^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:50:36 + | +LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: attempt to calculate the remainder with a divisor of zero + --> $DIR/issue-8460-const2.rs:53:36 + | +LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); + | ^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:53:36 + | +LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: attempt to calculate the remainder with a divisor of zero + --> $DIR/issue-8460-const2.rs:56:36 + | +LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); + | ^^^^^^^^ + +error: this expression will panic at runtime + --> $DIR/issue-8460-const2.rs:56:36 + | +LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: aborting due to 30 previous errors + diff --git a/src/test/ui/reify-intrinsic.rs b/src/test/ui/reify-intrinsic.rs new file mode 100644 index 0000000000000..09baa059e5567 --- /dev/null +++ b/src/test/ui/reify-intrinsic.rs @@ -0,0 +1,15 @@ +// check-fail + +#![feature(intrinsics)] + +fn a() { + let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + //~^ ERROR cannot coerce +} + +fn b() { + let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + //~^ ERROR casting +} + +fn main() {} diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr new file mode 100644 index 0000000000000..4a1bd77cf7ee9 --- /dev/null +++ b/src/test/ui/reify-intrinsic.stderr @@ -0,0 +1,22 @@ +error[E0308]: cannot coerce intrinsics to function pointers + --> $DIR/reify-intrinsic.rs:6:64 + | +LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + | ^^^^^^^^^^^^^^^^^^^ + | | + | cannot coerce intrinsics to function pointers + | help: use parentheses to call this function: `std::mem::transmute(...)` + | + = note: expected type `unsafe extern "rust-intrinsic" fn(isize) -> usize` + found type `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + +error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid + --> $DIR/reify-intrinsic.rs:11:13 + | +LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0606. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.rs b/src/test/ui/self/point-at-arbitrary-self-type-method.rs new file mode 100644 index 0000000000000..0f7deeacad292 --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.rs @@ -0,0 +1,9 @@ +struct A; + +impl A { + fn foo(self: Box) {} +} + +fn main() { + A.foo(); //~ ERROR E0599 +} diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr new file mode 100644 index 0000000000000..06dad7caa6735 --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `foo` found for type `A` in the current scope + --> $DIR/point-at-arbitrary-self-type-method.rs:8:7 + | +LL | struct A; + | --------- method `foo` not found for this +... +LL | fn foo(self: Box) {} + | --- the method is available for `std::boxed::Box` here +... +LL | A.foo(); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs new file mode 100644 index 0000000000000..53d992771186f --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs @@ -0,0 +1,10 @@ +trait B { fn foo(self: Box); } +struct A; + +impl B for A { + fn foo(self: Box) {} +} + +fn main() { + A.foo() //~ ERROR E0599 +} diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr new file mode 100644 index 0000000000000..90cd3b8074580 --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -0,0 +1,18 @@ +error[E0599]: no method named `foo` found for type `A` in the current scope + --> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7 + | +LL | trait B { fn foo(self: Box); } + | --- the method is available for `std::boxed::Box` here +LL | struct A; + | --------- method `foo` not found for this +... +LL | A.foo() + | ^^^ + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `foo`, perhaps you need to implement it: + candidate #1: `B` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index de699a69fa8bc..ce2919c8e7741 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -17,6 +17,13 @@ error[E0599]: no method named `b` found for type `S` in the current scope LL | struct S; | --------- method `b` not found for this ... +LL | fn b(&self) { } + | - + | | + | the method is available for `std::boxed::Box` here + | the method is available for `std::sync::Arc` here + | the method is available for `std::rc::Rc` here +... LL | S.b(); | ^ | diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index bde49ff391c8c..467b7771c152e 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -335,7 +335,7 @@ pub fn parse_config(args: Vec) -> Config { runtool: matches.opt_str("runtool"), host_rustcflags: matches.opt_str("host-rustcflags"), target_rustcflags: matches.opt_str("target-rustcflags"), - target: target, + target, host: opt_str2(matches.opt_str("host")), cdb, gdb, @@ -345,7 +345,7 @@ pub fn parse_config(args: Vec) -> Config { lldb_native_rust, llvm_version: matches.opt_str("llvm-version"), system_llvm: matches.opt_present("system-llvm"), - android_cross_path: android_cross_path, + android_cross_path, adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), adb_device_status: opt_str2(matches.opt_str("target")).contains("android")