Auto merge of #79138 - m-ou-se:rollup-owel5ld, r=m-ou-se
Rollup of 8 pull requests Successful merges: - #74293 (Rustdoc test compiler output color) - #78702 ([self-profiling] Include the estimated size of each cgu in the profile) - #79069 (Get rid of `highlight::Class::None`) - #79072 (Fix exhaustiveness in case a byte string literal is used at slice type) - #79120 (update rustfmt to v1.4.27) - #79125 (Get rid of clean::{Method, TyMethod}) - #79126 (Remove duplicate `Trait::auto` field) - #79130 (extend macro braces test) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c919f490bb
24 changed files with 325 additions and 141 deletions
|
@ -4338,7 +4338,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.4.26"
|
||||
version = "1.4.27"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.6.1",
|
||||
"anyhow",
|
||||
|
|
|
@ -97,14 +97,12 @@ pub fn compile_codegen_unit(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
cgu_name: Symbol,
|
||||
) -> (ModuleCodegen<ModuleLlvm>, u64) {
|
||||
let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string());
|
||||
let start_time = Instant::now();
|
||||
|
||||
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
|
||||
let (module, _) =
|
||||
tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
|
||||
let time_to_codegen = start_time.elapsed();
|
||||
drop(prof_timer);
|
||||
|
||||
// We assume that the cost to run LLVM on a CGU is proportional to
|
||||
// the time we needed for codegenning it.
|
||||
|
@ -112,6 +110,10 @@ pub fn compile_codegen_unit(
|
|||
|
||||
fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
let _prof_timer = tcx.prof.generic_activity_with_args(
|
||||
"codegen_module",
|
||||
&[cgu_name.to_string(), cgu.size_estimate().to_string()],
|
||||
);
|
||||
// Instantiate monomorphizations without filling out definitions yet...
|
||||
let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
|
||||
{
|
||||
|
|
|
@ -272,6 +272,28 @@ impl SelfProfilerRef {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_activity_with_args(
|
||||
&self,
|
||||
event_label: &'static str,
|
||||
event_args: &[String],
|
||||
) -> TimingGuard<'_> {
|
||||
self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
|
||||
let builder = EventIdBuilder::new(&profiler.profiler);
|
||||
let event_label = profiler.get_or_alloc_cached_string(event_label);
|
||||
let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) {
|
||||
let event_args: Vec<_> = event_args
|
||||
.iter()
|
||||
.map(|s| profiler.get_or_alloc_cached_string(&s[..]))
|
||||
.collect();
|
||||
builder.from_label_and_args(event_label, &event_args)
|
||||
} else {
|
||||
builder.from_label(event_label)
|
||||
};
|
||||
TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
|
||||
})
|
||||
}
|
||||
|
||||
/// Start profiling a query provider. Profiling continues until the
|
||||
/// TimingGuard returned from this call is dropped.
|
||||
#[inline(always)]
|
||||
|
|
|
@ -200,6 +200,11 @@ pub trait Emitter {
|
|||
true
|
||||
}
|
||||
|
||||
/// Checks if we can use colors in the current output stream.
|
||||
fn supports_color(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMap>>;
|
||||
|
||||
/// Formats the substitutions of the primary_span
|
||||
|
@ -504,6 +509,10 @@ impl Emitter for EmitterWriter {
|
|||
fn should_show_explain(&self) -> bool {
|
||||
!self.short_message
|
||||
}
|
||||
|
||||
fn supports_color(&self) -> bool {
|
||||
self.dst.supports_color()
|
||||
}
|
||||
}
|
||||
|
||||
/// An emitter that does nothing when emitting a diagnostic.
|
||||
|
@ -2057,6 +2066,14 @@ impl Destination {
|
|||
Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
|
||||
}
|
||||
}
|
||||
|
||||
fn supports_color(&self) -> bool {
|
||||
match *self {
|
||||
Self::Terminal(ref stream) => stream.supports_color(),
|
||||
Self::Buffered(ref buffer) => buffer.buffer().supports_color(),
|
||||
Self::Raw(_, supports_color) => supports_color,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WritableDst<'a> {
|
||||
|
|
|
@ -422,6 +422,12 @@ pub struct TypeckResults<'tcx> {
|
|||
/// Stores the type, expression, span and optional scope span of all types
|
||||
/// that are live across the yield of this generator (if a generator).
|
||||
pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>,
|
||||
|
||||
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
|
||||
/// as `&[u8]`, depending on the pattern in which they are used.
|
||||
/// This hashset records all instances where we behave
|
||||
/// like this to allow `const_to_pat` to reliably handle this situation.
|
||||
pub treat_byte_string_as_slice: ItemLocalSet,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeckResults<'tcx> {
|
||||
|
@ -448,6 +454,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
closure_captures: Default::default(),
|
||||
closure_min_captures: Default::default(),
|
||||
generator_interior_types: Default::default(),
|
||||
treat_byte_string_as_slice: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,6 +690,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
|
|||
ref closure_captures,
|
||||
ref closure_min_captures,
|
||||
ref generator_interior_types,
|
||||
ref treat_byte_string_as_slice,
|
||||
} = *self;
|
||||
|
||||
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
||||
|
@ -717,6 +725,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
|
|||
closure_captures.hash_stable(hcx, hasher);
|
||||
closure_min_captures.hash_stable(hcx, hasher);
|
||||
generator_interior_types.hash_stable(hcx, hasher);
|
||||
treat_byte_string_as_slice.hash_stable(hcx, hasher);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
/// Converts an evaluated constant to a pattern (if possible).
|
||||
/// This means aggregate values (like structs and enums) are converted
|
||||
/// to a pattern that matches the value (as if you'd compared via structural equality).
|
||||
#[instrument(skip(self))]
|
||||
pub(super) fn const_to_pat(
|
||||
&self,
|
||||
cv: &'tcx ty::Const<'tcx>,
|
||||
|
@ -25,15 +26,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
mir_structural_match_violation: bool,
|
||||
) -> Pat<'tcx> {
|
||||
debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
|
||||
debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
|
||||
|
||||
let pat = self.tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut convert = ConstToPat::new(self, id, span, infcx);
|
||||
convert.to_pat(cv, mir_structural_match_violation)
|
||||
});
|
||||
|
||||
debug!("const_to_pat: pat={:?}", pat);
|
||||
debug!(?pat);
|
||||
pat
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +59,8 @@ struct ConstToPat<'a, 'tcx> {
|
|||
infcx: InferCtxt<'a, 'tcx>,
|
||||
|
||||
include_lint_checks: bool,
|
||||
|
||||
treat_byte_string_as_slice: bool,
|
||||
}
|
||||
|
||||
mod fallback_to_const_ref {
|
||||
|
@ -88,6 +88,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
span: Span,
|
||||
infcx: InferCtxt<'a, 'tcx>,
|
||||
) -> Self {
|
||||
trace!(?pat_ctxt.typeck_results.hir_owner);
|
||||
ConstToPat {
|
||||
id,
|
||||
span,
|
||||
|
@ -97,6 +98,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
saw_const_match_error: Cell::new(false),
|
||||
saw_const_match_lint: Cell::new(false),
|
||||
behind_reference: Cell::new(false),
|
||||
treat_byte_string_as_slice: pat_ctxt
|
||||
.typeck_results
|
||||
.treat_byte_string_as_slice
|
||||
.contains(&id.local_id),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +158,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
cv: &'tcx ty::Const<'tcx>,
|
||||
mir_structural_match_violation: bool,
|
||||
) -> Pat<'tcx> {
|
||||
trace!(self.treat_byte_string_as_slice);
|
||||
// This method is just a wrapper handling a validity check; the heavy lifting is
|
||||
// performed by the recursive `recur` method, which is not meant to be
|
||||
// invoked except by this method.
|
||||
|
@ -384,7 +390,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
}
|
||||
PatKind::Wild
|
||||
}
|
||||
// `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
|
||||
// `&str` is represented as `ConstValue::Slice`, let's keep using this
|
||||
// optimization for now.
|
||||
ty::Str => PatKind::Constant { value: cv },
|
||||
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
|
||||
|
@ -393,11 +399,33 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
|
||||
// has no negative effects on pattern matching, even if we're actually matching on
|
||||
// arrays.
|
||||
ty::Array(..) |
|
||||
ty::Array(..) if !self.treat_byte_string_as_slice => {
|
||||
let old = self.behind_reference.replace(true);
|
||||
let array = tcx.deref_const(self.param_env.and(cv));
|
||||
let val = PatKind::Deref {
|
||||
subpattern: Pat {
|
||||
kind: Box::new(PatKind::Array {
|
||||
prefix: tcx
|
||||
.destructure_const(param_env.and(array))
|
||||
.fields
|
||||
.iter()
|
||||
.map(|val| self.recur(val, false))
|
||||
.collect::<Result<_, _>>()?,
|
||||
slice: None,
|
||||
suffix: vec![],
|
||||
}),
|
||||
span,
|
||||
ty: pointee_ty,
|
||||
},
|
||||
};
|
||||
self.behind_reference.set(old);
|
||||
val
|
||||
}
|
||||
ty::Array(elem_ty, _) |
|
||||
// Cannot merge this with the catch all branch below, because the `const_deref`
|
||||
// changes the type from slice to array, we need to keep the original type in the
|
||||
// pattern.
|
||||
ty::Slice(..) => {
|
||||
ty::Slice(elem_ty) => {
|
||||
let old = self.behind_reference.replace(true);
|
||||
let array = tcx.deref_const(self.param_env.and(cv));
|
||||
let val = PatKind::Deref {
|
||||
|
@ -413,7 +441,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
suffix: vec![],
|
||||
}),
|
||||
span,
|
||||
ty: pointee_ty,
|
||||
ty: tcx.mk_slice(elem_ty),
|
||||
},
|
||||
};
|
||||
self.behind_reference.set(old);
|
||||
|
|
|
@ -149,6 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
///
|
||||
/// Outside of this module, `check_pat_top` should always be used.
|
||||
/// Conversely, inside this module, `check_pat_top` should never be used.
|
||||
#[instrument(skip(self, ti))]
|
||||
fn check_pat(
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
|
@ -156,8 +157,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
def_bm: BindingMode,
|
||||
ti: TopInfo<'tcx>,
|
||||
) {
|
||||
debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
|
||||
|
||||
let path_res = match &pat.kind {
|
||||
PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)),
|
||||
_ => None,
|
||||
|
@ -398,6 +397,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let ty::Ref(_, inner_ty, _) = expected.kind() {
|
||||
if matches!(inner_ty.kind(), ty::Slice(_)) {
|
||||
let tcx = self.tcx;
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.treat_byte_string_as_slice
|
||||
.insert(lt.hir_id.local_id);
|
||||
pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
||||
wbcx.typeck_results.used_trait_imports = used_trait_imports;
|
||||
|
||||
wbcx.typeck_results.treat_byte_string_as_slice =
|
||||
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
|
||||
|
||||
wbcx.typeck_results.closure_captures =
|
||||
mem::take(&mut self.typeck_results.borrow_mut().closure_captures);
|
||||
|
||||
|
|
|
@ -193,7 +193,6 @@ crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
|
|||
let trait_items =
|
||||
cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
|
||||
|
||||
let auto_trait = cx.tcx.trait_def(did).has_auto_impl;
|
||||
let predicates = cx.tcx.predicates_of(did);
|
||||
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
|
||||
let generics = filter_non_trait_generics(did, generics);
|
||||
|
@ -201,7 +200,6 @@ crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
|
|||
let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight);
|
||||
let is_auto = cx.tcx.trait_is_auto(did);
|
||||
clean::Trait {
|
||||
auto: auto_trait,
|
||||
unsafety: cx.tcx.trait_def(did).unsafety,
|
||||
generics,
|
||||
items: trait_items,
|
||||
|
|
|
@ -883,14 +883,12 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Clean<Method>
|
||||
for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId, Option<hir::Defaultness>)
|
||||
{
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Method {
|
||||
impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Function {
|
||||
let (generics, decl) =
|
||||
enter_impl_trait(cx, || (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
|
||||
let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
|
||||
Method { decl, generics, header: self.0.header, defaultness: self.3, all_types, ret_types }
|
||||
Function { decl, generics, header: self.0.header, all_types, ret_types }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,7 +1022,6 @@ impl Clean<Item> for doctree::Trait<'_> {
|
|||
stability: cx.stability(self.id),
|
||||
deprecation: cx.deprecation(self.id).clean(cx),
|
||||
kind: TraitItem(Trait {
|
||||
auto: self.is_auto.clean(cx),
|
||||
unsafety: self.unsafety,
|
||||
items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
|
||||
generics: self.generics.clean(cx),
|
||||
|
@ -1107,20 +1104,20 @@ impl Clean<Item> for hir::TraitItem<'_> {
|
|||
AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e)))
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
let mut m = (sig, &self.generics, body, None).clean(cx);
|
||||
let mut m = (sig, &self.generics, body).clean(cx);
|
||||
if m.header.constness == hir::Constness::Const
|
||||
&& is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some()
|
||||
{
|
||||
m.header.constness = hir::Constness::NotConst;
|
||||
}
|
||||
MethodItem(m)
|
||||
MethodItem(m, None)
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
|
||||
let (generics, decl) = enter_impl_trait(cx, || {
|
||||
(self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
|
||||
});
|
||||
let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
|
||||
let mut t = TyMethod { header: sig.header, decl, generics, all_types, ret_types };
|
||||
let mut t = Function { header: sig.header, decl, generics, all_types, ret_types };
|
||||
if t.header.constness == hir::Constness::Const
|
||||
&& is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some()
|
||||
{
|
||||
|
@ -1153,13 +1150,13 @@ impl Clean<Item> for hir::ImplItem<'_> {
|
|||
AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr)))
|
||||
}
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
let mut m = (sig, &self.generics, body, Some(self.defaultness)).clean(cx);
|
||||
let mut m = (sig, &self.generics, body).clean(cx);
|
||||
if m.header.constness == hir::Constness::Const
|
||||
&& is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some()
|
||||
{
|
||||
m.header.constness = hir::Constness::NotConst;
|
||||
}
|
||||
MethodItem(m)
|
||||
MethodItem(m, Some(self.defaultness))
|
||||
}
|
||||
hir::ImplItemKind::TyAlias(ref ty) => {
|
||||
let type_ = ty.clean(cx);
|
||||
|
@ -1235,21 +1232,23 @@ impl Clean<Item> for ty::AssocItem {
|
|||
ty::ImplContainer(_) => Some(self.defaultness),
|
||||
ty::TraitContainer(_) => None,
|
||||
};
|
||||
MethodItem(Method {
|
||||
generics,
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
unsafety: sig.unsafety(),
|
||||
abi: sig.abi(),
|
||||
constness,
|
||||
asyncness,
|
||||
MethodItem(
|
||||
Function {
|
||||
generics,
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
unsafety: sig.unsafety(),
|
||||
abi: sig.abi(),
|
||||
constness,
|
||||
asyncness,
|
||||
},
|
||||
all_types,
|
||||
ret_types,
|
||||
},
|
||||
defaultness,
|
||||
all_types,
|
||||
ret_types,
|
||||
})
|
||||
)
|
||||
} else {
|
||||
TyMethodItem(TyMethod {
|
||||
TyMethodItem(Function {
|
||||
generics,
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
|
|
|
@ -227,12 +227,8 @@ impl Item {
|
|||
|
||||
crate fn is_default(&self) -> bool {
|
||||
match self.kind {
|
||||
ItemKind::MethodItem(ref meth) => {
|
||||
if let Some(defaultness) = meth.defaultness {
|
||||
defaultness.has_value() && !defaultness.is_final()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
ItemKind::MethodItem(_, Some(defaultness)) => {
|
||||
defaultness.has_value() && !defaultness.is_final()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
@ -264,9 +260,9 @@ crate enum ItemKind {
|
|||
ImplItem(Impl),
|
||||
/// A method signature only. Used for required methods in traits (ie,
|
||||
/// non-default-methods).
|
||||
TyMethodItem(TyMethod),
|
||||
TyMethodItem(Function),
|
||||
/// A method with a body.
|
||||
MethodItem(Method),
|
||||
MethodItem(Function, Option<hir::Defaultness>),
|
||||
StructFieldItem(Type),
|
||||
VariantItem(Variant),
|
||||
/// `fn`s from an extern block
|
||||
|
@ -910,25 +906,6 @@ crate struct Generics {
|
|||
crate where_predicates: Vec<WherePredicate>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct Method {
|
||||
crate generics: Generics,
|
||||
crate decl: FnDecl,
|
||||
crate header: hir::FnHeader,
|
||||
crate defaultness: Option<hir::Defaultness>,
|
||||
crate all_types: Vec<(Type, TypeKind)>,
|
||||
crate ret_types: Vec<(Type, TypeKind)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct TyMethod {
|
||||
crate header: hir::FnHeader,
|
||||
crate decl: FnDecl,
|
||||
crate generics: Generics,
|
||||
crate all_types: Vec<(Type, TypeKind)>,
|
||||
crate ret_types: Vec<(Type, TypeKind)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct Function {
|
||||
crate decl: FnDecl,
|
||||
|
@ -1026,7 +1003,6 @@ impl GetDefId for FnRetTy {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct Trait {
|
||||
crate auto: bool,
|
||||
crate unsafety: hir::Unsafety,
|
||||
crate items: Vec<Item>,
|
||||
crate generics: Generics,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_errors::{ColorConfig, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{HirId, CRATE_HIR_ID};
|
||||
use rustc_interface::interface;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{self, CrateType};
|
||||
use rustc_session::config::{self, CrateType, ErrorOutputType};
|
||||
use rustc_session::{lint, DiagnosticOutput, Session};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
|
@ -248,7 +248,8 @@ fn run_test(
|
|||
outdir: DirState,
|
||||
path: PathBuf,
|
||||
) -> Result<(), TestFailure> {
|
||||
let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts, edition);
|
||||
let (test, line_offset, supports_color) =
|
||||
make_test(test, Some(cratename), as_test_harness, opts, edition);
|
||||
|
||||
let output_file = outdir.path().join("rust_out");
|
||||
|
||||
|
@ -293,6 +294,20 @@ fn run_test(
|
|||
path.to_str().expect("target path must be valid unicode").to_string()
|
||||
}
|
||||
});
|
||||
if let ErrorOutputType::HumanReadable(kind) = options.error_format {
|
||||
let (_, color_config) = kind.unzip();
|
||||
match color_config {
|
||||
ColorConfig::Never => {
|
||||
compiler.arg("--color").arg("never");
|
||||
}
|
||||
ColorConfig::Always => {
|
||||
compiler.arg("--color").arg("always");
|
||||
}
|
||||
ColorConfig::Auto => {
|
||||
compiler.arg("--color").arg(if supports_color { "always" } else { "never" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compiler.arg("-");
|
||||
compiler.stdin(Stdio::piped());
|
||||
|
@ -320,7 +335,10 @@ fn run_test(
|
|||
(true, false) => {}
|
||||
(false, true) => {
|
||||
if !error_codes.is_empty() {
|
||||
error_codes.retain(|err| !out.contains(&format!("error[{}]: ", err)));
|
||||
// We used to check if the output contained "error[{}]: " but since we added the
|
||||
// colored output, we can't anymore because of the color escape characters before
|
||||
// the ":".
|
||||
error_codes.retain(|err| !out.contains(&format!("error[{}]", err)));
|
||||
|
||||
if !error_codes.is_empty() {
|
||||
return Err(TestFailure::MissingErrorCodes(error_codes));
|
||||
|
@ -362,18 +380,19 @@ fn run_test(
|
|||
}
|
||||
|
||||
/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of
|
||||
/// lines before the test code begins.
|
||||
/// lines before the test code begins as well as if the output stream supports colors or not.
|
||||
crate fn make_test(
|
||||
s: &str,
|
||||
cratename: Option<&str>,
|
||||
dont_insert_main: bool,
|
||||
opts: &TestOptions,
|
||||
edition: Edition,
|
||||
) -> (String, usize) {
|
||||
) -> (String, usize, bool) {
|
||||
let (crate_attrs, everything_else, crates) = partition_source(s);
|
||||
let everything_else = everything_else.trim();
|
||||
let mut line_offset = 0;
|
||||
let mut prog = String::new();
|
||||
let mut supports_color = false;
|
||||
|
||||
if opts.attrs.is_empty() && !opts.display_warnings {
|
||||
// If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some
|
||||
|
@ -399,7 +418,7 @@ crate fn make_test(
|
|||
// crate already is included.
|
||||
let result = rustc_driver::catch_fatal_errors(|| {
|
||||
rustc_span::with_session_globals(edition, || {
|
||||
use rustc_errors::emitter::EmitterWriter;
|
||||
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
||||
use rustc_errors::Handler;
|
||||
use rustc_parse::maybe_new_parser_from_source_str;
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
@ -411,8 +430,13 @@ crate fn make_test(
|
|||
// Any errors in parsing should also appear when the doctest is compiled for real, so just
|
||||
// send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
|
||||
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
supports_color =
|
||||
EmitterWriter::stderr(ColorConfig::Auto, None, false, false, Some(80), false)
|
||||
.supports_color();
|
||||
|
||||
let emitter =
|
||||
EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
|
||||
|
||||
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
|
||||
let handler = Handler::with_emitter(false, None, box emitter);
|
||||
let sess = ParseSess::with_span_handler(handler, sm);
|
||||
|
@ -482,7 +506,7 @@ crate fn make_test(
|
|||
Err(ErrorReported) => {
|
||||
// If the parser panicked due to a fatal error, pass the test code through unchanged.
|
||||
// The error will be reported during compilation.
|
||||
return (s.to_owned(), 0);
|
||||
return (s.to_owned(), 0, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -532,7 +556,7 @@ crate fn make_test(
|
|||
|
||||
debug!("final doctest:\n{}", prog);
|
||||
|
||||
(prog, line_offset)
|
||||
(prog, line_offset, supports_color)
|
||||
}
|
||||
|
||||
// FIXME(aburka): use a real parser to deal with multiline attributes
|
||||
|
|
|
@ -11,8 +11,8 @@ fn main() {
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -26,8 +26,8 @@ fn main() {
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -44,8 +44,8 @@ use asdf::qwop;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 3));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -61,8 +61,8 @@ use asdf::qwop;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -79,8 +79,8 @@ use std::*;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -98,8 +98,8 @@ use asdf::qwop;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -115,8 +115,8 @@ use asdf::qwop;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -134,8 +134,8 @@ use asdf::qwop;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 3));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 3));
|
||||
|
||||
// Adding more will also bump the returned line offset.
|
||||
opts.attrs.push("feature(hella_dope)".to_string());
|
||||
|
@ -147,8 +147,8 @@ use asdf::qwop;
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 4));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -164,8 +164,8 @@ fn main() {
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -180,8 +180,8 @@ fn main() {
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 1));
|
||||
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -196,8 +196,8 @@ fn main() {
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -210,8 +210,8 @@ assert_eq!(2+2, 4);";
|
|||
//Ceci n'est pas une `fn main`
|
||||
assert_eq!(2+2, 4);"
|
||||
.to_string();
|
||||
let output = make_test(input, None, true, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 1));
|
||||
let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -224,8 +224,8 @@ fn make_test_display_warnings() {
|
|||
assert_eq!(2+2, 4);
|
||||
}"
|
||||
.to_string();
|
||||
let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 1));
|
||||
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -242,8 +242,8 @@ assert_eq!(2+2, 4);
|
|||
}"
|
||||
.to_string();
|
||||
|
||||
let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 2));
|
||||
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
|
||||
let input = "extern crate hella_qwop;
|
||||
assert_eq!(asdf::foo, 4);";
|
||||
|
@ -256,8 +256,8 @@ assert_eq!(asdf::foo, 4);
|
|||
}"
|
||||
.to_string();
|
||||
|
||||
let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 3));
|
||||
let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -274,6 +274,6 @@ test_wrapper! {
|
|||
}"
|
||||
.to_string();
|
||||
|
||||
let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!(output, (expected, 1));
|
||||
let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
|
||||
assert_eq!((output, len), (expected, 1));
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ fn write_footer(out: &mut String, playground_button: Option<&str>) {
|
|||
/// How a span of text is classified. Mostly corresponds to token kinds.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum Class {
|
||||
None,
|
||||
Comment,
|
||||
DocComment,
|
||||
Attribute,
|
||||
|
@ -89,7 +88,6 @@ impl Class {
|
|||
/// Returns the css class expected by rustdoc for each `Class`.
|
||||
fn as_html(self) -> &'static str {
|
||||
match self {
|
||||
Class::None => "",
|
||||
Class::Comment => "comment",
|
||||
Class::DocComment => "doccomment",
|
||||
Class::Attribute => "attribute",
|
||||
|
@ -112,7 +110,7 @@ impl Class {
|
|||
}
|
||||
|
||||
enum Highlight<'a> {
|
||||
Token { text: &'a str, class: Class },
|
||||
Token { text: &'a str, class: Option<Class> },
|
||||
EnterSpan { class: Class },
|
||||
ExitSpan,
|
||||
}
|
||||
|
@ -166,8 +164,9 @@ impl<'a> Classifier<'a> {
|
|||
/// a couple of following ones as well.
|
||||
fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
|
||||
let lookahead = self.peek();
|
||||
let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
|
||||
let class = match token {
|
||||
TokenKind::Whitespace => Class::None,
|
||||
TokenKind::Whitespace => return no_highlight(sink),
|
||||
TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => {
|
||||
if doc_style.is_some() {
|
||||
Class::DocComment
|
||||
|
@ -192,12 +191,12 @@ impl<'a> Classifier<'a> {
|
|||
TokenKind::And => match lookahead {
|
||||
Some(TokenKind::And) => {
|
||||
let _and = self.tokens.next();
|
||||
sink(Highlight::Token { text: "&&", class: Class::Op });
|
||||
sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
|
||||
return;
|
||||
}
|
||||
Some(TokenKind::Eq) => {
|
||||
let _eq = self.tokens.next();
|
||||
sink(Highlight::Token { text: "&=", class: Class::Op });
|
||||
sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
|
||||
return;
|
||||
}
|
||||
Some(TokenKind::Whitespace) => Class::Op,
|
||||
|
@ -228,7 +227,7 @@ impl<'a> Classifier<'a> {
|
|||
| TokenKind::At
|
||||
| TokenKind::Tilde
|
||||
| TokenKind::Colon
|
||||
| TokenKind::Unknown => Class::None,
|
||||
| TokenKind::Unknown => return no_highlight(sink),
|
||||
|
||||
TokenKind::Question => Class::QuestionMark,
|
||||
|
||||
|
@ -237,7 +236,7 @@ impl<'a> Classifier<'a> {
|
|||
self.in_macro_nonterminal = true;
|
||||
Class::MacroNonTerminal
|
||||
}
|
||||
_ => Class::None,
|
||||
_ => return no_highlight(sink),
|
||||
},
|
||||
|
||||
// This might be the start of an attribute. We're going to want to
|
||||
|
@ -253,8 +252,8 @@ impl<'a> Classifier<'a> {
|
|||
self.in_attribute = true;
|
||||
sink(Highlight::EnterSpan { class: Class::Attribute });
|
||||
}
|
||||
sink(Highlight::Token { text: "#", class: Class::None });
|
||||
sink(Highlight::Token { text: "!", class: Class::None });
|
||||
sink(Highlight::Token { text: "#", class: None });
|
||||
sink(Highlight::Token { text: "!", class: None });
|
||||
return;
|
||||
}
|
||||
// Case 2: #[outer_attribute]
|
||||
|
@ -264,16 +263,16 @@ impl<'a> Classifier<'a> {
|
|||
}
|
||||
_ => (),
|
||||
}
|
||||
Class::None
|
||||
return no_highlight(sink);
|
||||
}
|
||||
TokenKind::CloseBracket => {
|
||||
if self.in_attribute {
|
||||
self.in_attribute = false;
|
||||
sink(Highlight::Token { text: "]", class: Class::None });
|
||||
sink(Highlight::Token { text: "]", class: None });
|
||||
sink(Highlight::ExitSpan);
|
||||
return;
|
||||
}
|
||||
Class::None
|
||||
return no_highlight(sink);
|
||||
}
|
||||
TokenKind::Literal { kind, .. } => match kind {
|
||||
// Text literals.
|
||||
|
@ -309,7 +308,7 @@ impl<'a> Classifier<'a> {
|
|||
};
|
||||
// Anything that didn't return above is the simple case where we the
|
||||
// class just spans a single token, so we can use the `string` method.
|
||||
sink(Highlight::Token { text, class });
|
||||
sink(Highlight::Token { text, class: Some(class) });
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> Option<TokenKind> {
|
||||
|
@ -339,10 +338,10 @@ fn exit_span(out: &mut String) {
|
|||
/// ```
|
||||
/// The latter can be thought of as a shorthand for the former, which is more
|
||||
/// flexible.
|
||||
fn string<T: Display>(out: &mut String, text: T, klass: Class) {
|
||||
fn string<T: Display>(out: &mut String, text: T, klass: Option<Class>) {
|
||||
match klass {
|
||||
Class::None => write!(out, "{}", text).unwrap(),
|
||||
klass => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text).unwrap(),
|
||||
None => write!(out, "{}", text).unwrap(),
|
||||
Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -243,7 +243,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
|||
.collect::<Vec<Cow<'_, str>>>()
|
||||
.join("\n");
|
||||
let krate = krate.as_ref().map(|s| &**s);
|
||||
let (test, _) = doctest::make_test(&test, krate, false, &Default::default(), edition);
|
||||
let (test, _, _) =
|
||||
doctest::make_test(&test, krate, false, &Default::default(), edition);
|
||||
let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" };
|
||||
|
||||
let edition_string = format!("&edition={}", edition);
|
||||
|
|
|
@ -167,7 +167,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
|
|||
crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
|
||||
let (all_types, ret_types) = match item.kind {
|
||||
clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
|
||||
clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
|
||||
clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types),
|
||||
clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
|
||||
_ => return None,
|
||||
};
|
||||
|
|
|
@ -2589,7 +2589,9 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
|
|||
for (pos, m) in provided.iter().enumerate() {
|
||||
render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
|
||||
match m.kind {
|
||||
clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
|
||||
clean::MethodItem(ref inner, _)
|
||||
if !inner.generics.where_predicates.is_empty() =>
|
||||
{
|
||||
write!(w, ",\n {{ ... }}\n");
|
||||
}
|
||||
_ => {
|
||||
|
@ -2759,7 +2761,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
|
|||
}
|
||||
write_loading_content(w, "</div>");
|
||||
|
||||
if t.auto {
|
||||
if t.is_auto {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"synthetic-implementors",
|
||||
|
@ -2790,7 +2792,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
|
|||
);
|
||||
write_loading_content(w, "</div>");
|
||||
|
||||
if t.auto {
|
||||
if t.is_auto {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"synthetic-implementors",
|
||||
|
@ -2968,7 +2970,9 @@ fn render_assoc_item(
|
|||
match item.kind {
|
||||
clean::StrippedItem(..) => {}
|
||||
clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent),
|
||||
clean::MethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent),
|
||||
clean::MethodItem(ref m, _) => {
|
||||
method(w, item, m.header, &m.generics, &m.decl, link, parent)
|
||||
}
|
||||
clean::AssocConstItem(ref ty, ref default) => assoc_const(
|
||||
w,
|
||||
item,
|
||||
|
@ -3545,7 +3549,7 @@ fn render_deref_methods(
|
|||
|
||||
fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
|
||||
let self_type_opt = match item.kind {
|
||||
clean::MethodItem(ref method) => method.decl.self_type(),
|
||||
clean::MethodItem(ref method, _) => method.decl.self_type(),
|
||||
clean::TyMethodItem(ref method) => method.decl.self_type(),
|
||||
_ => None,
|
||||
};
|
||||
|
@ -3752,8 +3756,7 @@ fn render_impl(
|
|||
(true, " hidden")
|
||||
};
|
||||
match item.kind {
|
||||
clean::MethodItem(clean::Method { .. })
|
||||
| clean::TyMethodItem(clean::TyMethod { .. }) => {
|
||||
clean::MethodItem(..) | clean::TyMethodItem(_) => {
|
||||
// Only render when the method is not static or we allow static methods
|
||||
if render_method_item {
|
||||
let id = cx.derive_id(format!("{}.{}", item_type, name));
|
||||
|
@ -4454,7 +4457,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
|
|||
sidebar.push_str(&sidebar_assoc_items(it));
|
||||
|
||||
sidebar.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>");
|
||||
if t.auto {
|
||||
if t.is_auto {
|
||||
sidebar.push_str(
|
||||
"<a class=\"sidebar-title\" \
|
||||
href=\"#synthetic-implementors\">Auto Implementors</a>",
|
||||
|
|
|
@ -9,6 +9,17 @@ help: enclose the `const` expression in braces
|
|||
LL | let _: baz!({ N });
|
||||
| ^ ^
|
||||
|
||||
error: expressions must be enclosed in braces to be used as const generic arguments
|
||||
--> $DIR/macro_rules-braces.rs:54:17
|
||||
|
|
||||
LL | let _: baz!(10 + 7);
|
||||
| ^^^^^^
|
||||
|
|
||||
help: enclose the `const` expression in braces
|
||||
|
|
||||
LL | let _: baz!({ 10 + 7 });
|
||||
| ^ ^
|
||||
|
||||
error: constant expression depends on a generic parameter
|
||||
--> $DIR/macro_rules-braces.rs:10:13
|
||||
|
|
||||
|
@ -57,5 +68,5 @@ LL | let _: biz!({ N });
|
|||
= note: this may fail depending on what value the parameter takes
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
@ -9,6 +9,17 @@ help: enclose the `const` expression in braces
|
|||
LL | let _: baz!({ N });
|
||||
| ^ ^
|
||||
|
||||
error: expressions must be enclosed in braces to be used as const generic arguments
|
||||
--> $DIR/macro_rules-braces.rs:54:17
|
||||
|
|
||||
LL | let _: baz!(10 + 7);
|
||||
| ^^^^^^
|
||||
|
|
||||
help: enclose the `const` expression in braces
|
||||
|
|
||||
LL | let _: baz!({ 10 + 7 });
|
||||
| ^ ^
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/macro_rules-braces.rs:31:20
|
||||
|
|
||||
|
@ -41,5 +52,5 @@ LL | let _: biz!({ N });
|
|||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
@ -36,6 +36,26 @@ fn test<const N: usize>() {
|
|||
let _: baz!({{ N }}); //[min]~ ERROR generic parameters may not
|
||||
let _: biz!(N);
|
||||
let _: biz!({ N }); //[min]~ ERROR generic parameters may not
|
||||
let _: foo!(3);
|
||||
let _: foo!({ 3 });
|
||||
let _: foo!({{ 3 }});
|
||||
let _: bar!(3);
|
||||
let _: bar!({ 3 });
|
||||
let _: baz!(3);
|
||||
let _: baz!({ 3 });
|
||||
let _: baz!({{ 3 }});
|
||||
let _: biz!(3);
|
||||
let _: biz!({ 3 });
|
||||
let _: foo!(10 + 7);
|
||||
let _: foo!({ 10 + 7 });
|
||||
let _: foo!({{ 10 + 7 }});
|
||||
let _: bar!(10 + 7);
|
||||
let _: bar!({ 10 + 7 });
|
||||
let _: baz!(10 + 7); //~ ERROR expressions must be enclosed in braces
|
||||
let _: baz!({ 10 + 7 });
|
||||
let _: baz!({{ 10 + 7 }});
|
||||
let _: biz!(10 + 7);
|
||||
let _: biz!({ 10 + 7 });
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
36
src/test/ui/match/type_polymorphic_byte_str_literals.rs
Normal file
36
src/test/ui/match/type_polymorphic_byte_str_literals.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
#[deny(unreachable_patterns)]
|
||||
|
||||
fn parse_data1(data: &[u8]) -> u32 {
|
||||
match data {
|
||||
b"" => 1,
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_data2(data: &[u8]) -> u32 {
|
||||
match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered
|
||||
b"" => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_data3(data: &[u8; 0]) -> u8 {
|
||||
match data {
|
||||
b"" => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_data4(data: &[u8]) -> u8 {
|
||||
match data { //~ ERROR non-exhaustive patterns
|
||||
b"aaa" => 0,
|
||||
[_, _, _] => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_data5(data: &[u8; 3]) -> u8 {
|
||||
match data {
|
||||
b"aaa" => 0,
|
||||
[_, _, _] => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
21
src/test/ui/match/type_polymorphic_byte_str_literals.stderr
Normal file
21
src/test/ui/match/type_polymorphic_byte_str_literals.stderr
Normal file
|
@ -0,0 +1,21 @@
|
|||
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
|
||||
--> $DIR/type_polymorphic_byte_str_literals.rs:11:11
|
||||
|
|
||||
LL | match data {
|
||||
| ^^^^ pattern `&[_, ..]` not covered
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `&[u8]`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
|
||||
--> $DIR/type_polymorphic_byte_str_literals.rs:23:11
|
||||
|
|
||||
LL | match data {
|
||||
| ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `&[u8]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
|
@ -7,11 +7,11 @@ LL | match buf {
|
|||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `&[u8; 4]`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
||||
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
||||
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
||||
|
|
||||
LL | match buf {
|
||||
| ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
||||
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `&[u8]`
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 293d7d01118c9fb5479649399e1dae60322b8e09
|
||||
Subproject commit 580d826e9b0f407a2d4b36696cda2f0fa8d7ddaa
|
Loading…
Add table
Reference in a new issue