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:
bors 2020-11-17 15:27:29 +00:00
commit c919f490bb
24 changed files with 325 additions and 141 deletions

View file

@ -4338,7 +4338,7 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
version = "1.4.26"
version = "1.4.27"
dependencies = [
"annotate-snippets 0.6.1",
"anyhow",

View file

@ -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());
{

View file

@ -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)]

View file

@ -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> {

View file

@ -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);
})
}
}

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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,

View file

@ -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 {

View file

@ -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,

View file

@ -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

View file

@ -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));
}

View file

@ -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(),
}
}

View file

@ -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(") { "&amp;version=nightly" } else { "" };
let edition_string = format!("&amp;edition={}", edition);

View file

@ -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,
};

View file

@ -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>",

View file

@ -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

View file

@ -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

View file

@ -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() {

View 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() {}

View 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`.

View file

@ -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