Auto merge of #63779 - Centril:rollup-sx96dli, r=Centril

Rollup of 7 pull requests

Successful merges:

 - #63721 (Do not emit JSON dumps of diagnostic codes)
 - #63753 (Bump toml dependency.)
 - #63755 (Use dedicated type for spans in pre-expansion gating.)
 - #63759 (Allow 'default async fn' to parse.)
 - #63760 (Update books)
 - #63762 (`async_await` was stabilized in 1.39.0, not 1.38.0.)
 - #63766 (Remove some duplication when resolving constants)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-08-21 11:40:23 +00:00
commit 7b0085a613
24 changed files with 177 additions and 239 deletions

View file

@ -185,7 +185,7 @@ dependencies = [
"serde",
"serde_json",
"time",
"toml 0.4.10",
"toml",
]
[[package]]
@ -202,7 +202,7 @@ name = "build-manifest"
version = "0.1.0"
dependencies = [
"serde",
"toml 0.4.10",
"toml",
]
[[package]]
@ -316,7 +316,7 @@ dependencies = [
"tar",
"tempfile",
"termcolor",
"toml 0.5.3",
"toml",
"unicode-width",
"url 2.1.0",
"walkdir",
@ -442,7 +442,7 @@ dependencies = [
"semver",
"serde",
"smallvec",
"toml 0.5.3",
"toml",
"unicode-normalization",
"url 2.1.0",
]
@ -946,6 +946,7 @@ name = "error_index_generator"
version = "0.0.0"
dependencies = [
"rustdoc",
"walkdir",
]
[[package]]
@ -1785,7 +1786,7 @@ dependencies = [
"serde_json",
"shlex",
"tempfile",
"toml 0.5.3",
"toml",
"toml-query",
]
@ -2760,7 +2761,7 @@ dependencies = [
"tokio",
"tokio-process",
"tokio-timer",
"toml 0.5.3",
"toml",
"url 1.7.2",
"walkdir",
]
@ -3590,7 +3591,7 @@ dependencies = [
"serde_json",
"structopt",
"term 0.6.0",
"toml 0.5.3",
"toml",
"unicode-segmentation",
"unicode-width",
"unicode_categories",
@ -4382,15 +4383,6 @@ dependencies = [
"tokio-reactor",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.5.3"
@ -4411,7 +4403,7 @@ dependencies = [
"is-match",
"lazy_static 1.3.0",
"regex",
"toml 0.5.3",
"toml",
"toml-query_derive",
]

View file

@ -44,7 +44,7 @@ cc = "1.0.35"
libc = "0.2"
serde = { version = "1.0.8", features = ["derive"] }
serde_json = "1.0.2"
toml = "0.4"
toml = "0.5"
lazy_static = "1.3.0"
time = "0.1"
petgraph = "0.4.13"

View file

@ -825,8 +825,7 @@ impl Step for ErrorIndex {
index.arg(crate::channel::CFG_RELEASE_NUM);
// FIXME: shouldn't have to pass this env var
index.env("CFG_BUILD", &builder.config.build)
.env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
index.env("CFG_BUILD", &builder.config.build);
builder.run(&mut index);
}

View file

@ -1535,8 +1535,7 @@ impl Step for ErrorIndex {
);
tool.arg("markdown")
.arg(&output)
.env("CFG_BUILD", &builder.config.build)
.env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
.env("CFG_BUILD", &builder.config.build);
builder.info(&format!("Testing error-index stage{}", compiler.stage));
let _time = util::timeit(&builder);

@ -1 +1 @@
Subproject commit c5da1e11915d3f28266168baaf55822f7e3fe999
Subproject commit 432ca26686c11d396eed6a59499f93ce1bf2433c

@ -1 +1 @@
Subproject commit 8a7d05615e5bc0a7fb961b4919c44f5221ee54da
Subproject commit 38b9a76bc8b59ac862663807fc51c9b757337fd6

@ -1 +1 @@
Subproject commit b4b3536839042a6743fc76f0d9ad2a812020aeaa
Subproject commit d191a0cdd3b92648e0f1e53b13140a14677cc65b

@ -1 +1 @@
Subproject commit f2c15ba5ee89ae9469a2cf60494977749901d764
Subproject commit 580839d90aacd537f0293697096fa8355bc4e673

View file

@ -8,7 +8,7 @@ use crate::hir::def_id::DefId;
use crate::ty::subst::{Kind, UnpackedKind, SubstsRef};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::error::{ExpectedFound, TypeError};
use crate::mir::interpret::{ConstValue, Scalar, GlobalId};
use crate::mir::interpret::{ConstValue, Scalar};
use std::rc::Rc;
use std::iter;
use rustc_target::spec::abi;
@ -551,26 +551,8 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
let tcx = relation.tcx();
let eagerly_eval = |x: &'tcx ty::Const<'tcx>| {
if let ConstValue::Unevaluated(def_id, substs) = x.val {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty();
if !substs.has_local_value() {
let instance = ty::Instance::resolve(
tcx.global_tcx(),
param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
if let Ok(ct) = tcx.const_eval(param_env.and(cid)) {
return ct.val;
}
}
}
if !x.val.has_local_value() {
return x.eval(tcx, relation.param_env()).val;
}
x.val
};

View file

@ -2299,23 +2299,33 @@ impl<'tcx> Const<'tcx> {
assert_eq!(self.ty, ty);
// if `ty` does not depend on generic parameters, use an empty param_env
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
self.eval(tcx, param_env).val.try_to_bits(size)
}
#[inline]
pub fn eval(
&self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> &Const<'tcx> {
// FIXME(const_generics): this doesn't work right now,
// because it tries to relate an `Infer` to a `Param`.
match self.val {
// FIXME(const_generics): this doesn't work right now,
// because it tries to relate an `Infer` to a `Param`.
ConstValue::Unevaluated(did, substs) => {
// if `substs` has no unresolved components, use and empty param_env
let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts();
// try to resolve e.g. associated constants to their definition on an impl
let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
let instance = match ty::Instance::resolve(tcx, param_env, did, substs) {
Some(instance) => instance,
None => return self,
};
let gid = GlobalId {
instance,
promoted: None,
};
let evaluated = tcx.const_eval(param_env.and(gid)).ok()?;
evaluated.val.try_to_bits(size)
tcx.const_eval(param_env.and(gid)).unwrap_or(self)
},
// otherwise just extract a `ConstValue`'s bits if possible
_ => self.val.try_to_bits(size),
_ => self,
}
}

View file

@ -1,93 +0,0 @@
//! This module contains utilities for outputting metadata for diagnostic errors.
//!
//! Each set of errors is mapped to a metadata file by a name, which is
//! currently always a crate name.
use std::collections::BTreeMap;
use std::env;
use std::fs::{remove_file, create_dir_all, File};
use std::io::Write;
use std::path::PathBuf;
use std::error::Error;
use rustc_serialize::json::as_json;
use syntax_pos::{Span, FileName};
use crate::ext::base::ExtCtxt;
use crate::diagnostics::plugin::{ErrorMap, ErrorInfo};
/// JSON encodable/decodable version of `ErrorInfo`.
#[derive(PartialEq, RustcDecodable, RustcEncodable)]
pub struct ErrorMetadata {
pub description: Option<String>,
pub use_site: Option<ErrorLocation>
}
/// Mapping from error codes to metadata that can be (de)serialized.
pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
/// JSON encodable error location type with filename and line number.
#[derive(PartialEq, RustcDecodable, RustcEncodable)]
pub struct ErrorLocation {
pub filename: FileName,
pub line: usize
}
impl ErrorLocation {
/// Creates an error location from a span.
pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation {
let loc = ecx.source_map().lookup_char_pos(sp.lo());
ErrorLocation {
filename: loc.file.name.clone(),
line: loc.line
}
}
}
/// Gets the directory where metadata for a given `prefix` should be stored.
///
/// See `output_metadata`.
pub fn get_metadata_dir(prefix: &str) -> PathBuf {
env::var_os("RUSTC_ERROR_METADATA_DST")
.map(PathBuf::from)
.expect("env var `RUSTC_ERROR_METADATA_DST` isn't set")
.join(prefix)
}
/// Map `name` to a path in the given directory: <directory>/<name>.json
fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf {
directory.join(format!("{}.json", name))
}
/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`.
///
/// For our current purposes the prefix is the target architecture and the name is a crate name.
/// If an error occurs steps will be taken to ensure that no file is created.
pub fn output_metadata(ecx: &ExtCtxt<'_>, prefix: &str, name: &str, err_map: &ErrorMap)
-> Result<(), Box<dyn Error>>
{
// Create the directory to place the file in.
let metadata_dir = get_metadata_dir(prefix);
create_dir_all(&metadata_dir)?;
// Open the metadata file.
let metadata_path = get_metadata_path(metadata_dir, name);
let mut metadata_file = File::create(&metadata_path)?;
// Construct a serializable map.
let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| {
let key = k.as_str().to_string();
let value = ErrorMetadata {
description: description.map(|n| n.as_str().to_string()),
use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp))
};
(key, value)
}).collect::<ErrorMetadataMap>();
// Write the data to the file, deleting it if the write fails.
let result = write!(&mut metadata_file, "{}", as_json(&json_map));
if result.is_err() {
remove_file(&metadata_path)?;
}
Ok(result?)
}

View file

@ -1,5 +1,4 @@
use std::collections::BTreeMap;
use std::env;
use crate::ast::{self, Ident, Name};
use crate::source_map;
@ -12,8 +11,6 @@ use crate::tokenstream::{TokenTree};
use smallvec::smallvec;
use syntax_pos::Span;
use crate::diagnostics::metadata::output_metadata;
pub use errors::*;
// Maximum width of any line in an extended error description (inclusive).
@ -127,36 +124,13 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>,
token_tree: &[TokenTree])
-> Box<dyn MacResult+'cx> {
assert_eq!(token_tree.len(), 3);
let (crate_name, ident) = match (&token_tree[0], &token_tree[2]) {
(
// Crate name.
&TokenTree::Token(Token { kind: token::Ident(crate_name, _), .. }),
// DIAGNOSTICS ident.
&TokenTree::Token(Token { kind: token::Ident(name, _), span })
) => (crate_name, Ident::new(name, span)),
let ident = match &token_tree[2] {
// DIAGNOSTICS ident.
&TokenTree::Token(Token { kind: token::Ident(name, _), span })
=> Ident::new(name, span),
_ => unreachable!()
};
// Output error metadata to `tmp/extended-errors/<target arch>/<crate name>.json`
if let Ok(target_triple) = env::var("CFG_COMPILER_HOST_TRIPLE") {
ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| {
if let Err(e) = output_metadata(ecx,
&target_triple,
&crate_name.as_str(),
diagnostics) {
ecx.span_bug(span, &format!(
"error writing metadata for triple `{}` and crate `{}`, error: {}, \
cause: {:?}",
target_triple, crate_name, e.description(), e.source()
));
}
});
} else {
ecx.span_err(span, &format!(
"failed to write metadata for crate `{}` because $CFG_COMPILER_HOST_TRIPLE is not set",
crate_name));
}
// Construct the output expression.
let (count, expr) =
ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| {

View file

@ -855,7 +855,7 @@ declare_features! (
// Allows `const _: TYPE = VALUE`.
(accepted, underscore_const_names, "1.37.0", Some(54912), None),
// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions.
(accepted, async_await, "1.38.0", Some(50547), None),
(accepted, async_await, "1.39.0", Some(50547), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
@ -2423,16 +2423,19 @@ pub fn check_crate(krate: &ast::Crate,
};
macro_rules! gate_all {
($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); };
($spans:ident, $gate:ident, $msg:literal) => {
for span in &*sess.$spans.borrow() { gate_feature!(&ctx, $gate, *span, $msg); }
for span in &*sess.gated_spans.$spans.borrow() {
gate_feature!(&ctx, $gate, *span, $msg);
}
}
}
gate_all!(param_attr_spans, param_attrs, "attributes on function parameters are unstable");
gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental");
gate_all!(async_closure_spans, async_closure, "async closures are unstable");
gate_all!(yield_spans, generators, "yield syntax is experimental");
gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental");
gate_all!(param_attrs, "attributes on function parameters are unstable");
gate_all!(let_chains, "`let` expressions in this position are experimental");
gate_all!(async_closure, "async closures are unstable");
gate_all!(yields, generators, "yield syntax is experimental");
gate_all!(or_patterns, "or-patterns syntax is experimental");
let visitor = &mut PostExpansionVisitor {
context: &ctx,

View file

@ -124,7 +124,6 @@ pub mod diagnostics {
#[macro_use]
pub mod macros;
pub mod plugin;
pub mod metadata;
}
// N.B., this module needs to be declared first so diagnostics are

View file

@ -21,9 +21,8 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
impl<'a> Parser<'a> {
crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
let attrs = self.parse_outer_attributes()?;
attrs.iter().for_each(|a|
self.sess.param_attr_spans.borrow_mut().push(a.span)
);
self.sess.gated_spans.param_attrs.borrow_mut()
.extend(attrs.iter().map(|a| a.span));
Ok(attrs)
}

View file

@ -39,6 +39,22 @@ crate mod unescape_error_reporting;
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
/// Collected spans during parsing for places where a certain feature was
/// used and should be feature gated accordingly in `check_crate`.
#[derive(Default)]
pub struct GatedSpans {
/// Spans collected for gating `param_attrs`, e.g. `fn foo(#[attr] x: u8) {}`.
pub param_attrs: Lock<Vec<Span>>,
/// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`.
pub let_chains: Lock<Vec<Span>>,
/// Spans collected for gating `async_closure`, e.g. `async || ..`.
pub async_closure: Lock<Vec<Span>>,
/// Spans collected for gating `yield e?` expressions (`generators` gate).
pub yields: Lock<Vec<Span>>,
/// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`.
pub or_patterns: Lock<Vec<Span>>,
}
/// Info about a parsing session.
pub struct ParseSess {
pub span_diagnostic: Handler,
@ -58,16 +74,8 @@ pub struct ParseSess {
/// operation token that followed it, but that the parser cannot identify without further
/// analysis.
pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
pub param_attr_spans: Lock<Vec<Span>>,
// Places where `let` exprs were used and should be feature gated according to `let_chains`.
pub let_chains_spans: Lock<Vec<Span>>,
// Places where `async || ..` exprs were used and should be feature gated.
pub async_closure_spans: Lock<Vec<Span>>,
// Places where `yield e?` exprs were used and should be feature gated.
pub yield_spans: Lock<Vec<Span>>,
pub injected_crate_name: Once<Symbol>,
// Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated.
pub or_pattern_spans: Lock<Vec<Span>>,
pub gated_spans: GatedSpans,
}
impl ParseSess {
@ -93,12 +101,8 @@ impl ParseSess {
buffered_lints: Lock::new(vec![]),
edition: ExpnId::root().expn_data().edition,
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
yield_spans: Lock::new(Vec::new()),
injected_crate_name: Once::new(),
or_pattern_spans: Lock::new(Vec::new()),
gated_spans: GatedSpans::default(),
}
}

View file

@ -999,7 +999,7 @@ impl<'a> Parser<'a> {
}
let span = lo.to(hi);
self.sess.yield_spans.borrow_mut().push(span);
self.sess.gated_spans.yields.borrow_mut().push(span);
} else if self.eat_keyword(kw::Let) {
return self.parse_let_expr(attrs);
} else if is_span_rust_2018 && self.eat_keyword(kw::Await) {
@ -1111,7 +1111,7 @@ impl<'a> Parser<'a> {
};
if asyncness.is_async() {
// Feature gate `async ||` closures.
self.sess.async_closure_spans.borrow_mut().push(self.prev_span);
self.sess.gated_spans.async_closure.borrow_mut().push(self.prev_span);
}
let capture_clause = self.parse_capture_clause();
@ -1234,7 +1234,7 @@ impl<'a> Parser<'a> {
if let ExprKind::Let(..) = cond.node {
// Remove the last feature gating of a `let` expression since it's stable.
let last = self.sess.let_chains_spans.borrow_mut().pop();
let last = self.sess.gated_spans.let_chains.borrow_mut().pop();
debug_assert_eq!(cond.span, last.unwrap());
}
@ -1252,7 +1252,7 @@ impl<'a> Parser<'a> {
|this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
)?;
let span = lo.to(expr.span);
self.sess.let_chains_spans.borrow_mut().push(span);
self.sess.gated_spans.let_chains.borrow_mut().push(span);
Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs))
}

View file

@ -825,6 +825,7 @@ impl<'a> Parser<'a> {
self.is_keyword_ahead(1, &[
kw::Impl,
kw::Const,
kw::Async,
kw::Fn,
kw::Unsafe,
kw::Extern,

View file

@ -123,7 +123,7 @@ impl<'a> Parser<'a> {
let or_pattern_span = lo.to(self.prev_span);
self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span);
self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span);
Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
}

View file

@ -0,0 +1,14 @@
// Ensure that `default async fn` will parse.
// See issue #63716 for details.
// check-pass
// edition:2018
#![feature(specialization)]
fn main() {}
#[cfg(FALSE)]
impl Foo for Bar {
default async fn baz() {}
}

View file

@ -5,5 +5,5 @@ authors = ["Alex Crichton <alex@alexcrichton.com>"]
edition = "2018"
[dependencies]
toml = "0.4"
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }

View file

@ -3,10 +3,14 @@ authors = ["The Rust Project Developers"]
name = "error_index_generator"
version = "0.0.0"
edition = "2018"
build = "build.rs"
[dependencies]
rustdoc = { path = "../../librustdoc" }
[build-dependencies]
walkdir = "2"
[[bin]]
name = "error_index_generator"
path = "main.rs"

View file

@ -0,0 +1,64 @@
use walkdir::WalkDir;
use std::path::PathBuf;
use std::{env, fs};
fn main() {
// The src directory (we are in src/tools/error_index_generator)
// Note that we could skip one of the .. but this ensures we at least loosely find the right
// directory.
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let dest = out_dir.join("error_codes.rs");
let mut idx = 0;
for entry in WalkDir::new("../../../src") {
let entry = entry.unwrap();
if entry.file_name() == "error_codes.rs" {
println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
let file = fs::read_to_string(entry.path()).unwrap()
.replace("use syntax::{register_diagnostics, register_long_diagnostics};", "")
.replace("use syntax::register_diagnostics;", "")
.replace("use syntax::register_long_diagnostics;", "");
let contents = format!("(|| {{\n{}\n}})();", file);
fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap();
idx += 1;
}
}
let mut all = String::new();
all.push_str("fn register_all() -> Vec<(&'static str, Option<&'static str>)> {\n");
all.push_str("let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();\n");
all.push_str(r#"
macro_rules! register_diagnostics {
($($code:tt),*) => {{
long_codes.extend([$(
stringify!($code),
)*].iter().cloned().map(|s| (s, None)).collect::<Vec<_>>());
}};
($($code:tt),*,) => {{
long_codes.extend([$(
stringify!($code),
)*].iter().cloned().map(|s| (s, None)));
}}
}
macro_rules! register_long_diagnostics {
($($code:tt: $description:tt),*) => {
{long_codes.extend([$(
(stringify!($code), Some(stringify!($description))),
)*].iter());}
};
($($code:tt: $description:tt),*,) => {
{long_codes.extend([$(
(stringify!($code), Some(stringify!($description))),
)*].iter());}
}
}"#);
for idx in 0..idx {
all.push_str(&format!(r#"include!(concat!(env!("OUT_DIR"), "/error_{}.rs"));"#, idx));
}
all.push_str("\nlong_codes\n");
all.push_str("}\n");
fs::write(&dest, all).unwrap();
}

View file

@ -2,22 +2,26 @@
extern crate env_logger;
extern crate syntax;
extern crate serialize as rustc_serialize;
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs::{self, read_dir, File};
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::cell::RefCell;
use syntax::edition::DEFAULT_EDITION;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, Playground};
use rustc_serialize::json;
pub struct ErrorMetadata {
pub description: Option<String>,
}
/// Mapping from error codes to metadata that can be (de)serialized.
pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
enum OutputFormat {
HTML(HTMLFormatter),
@ -80,11 +84,7 @@ impl Formatter for HTMLFormatter {
Some(_) => "error-described",
None => "error-undescribed",
};
let use_desc = match info.use_site {
Some(_) => "error-used",
None => "error-unused",
};
write!(output, "<div class=\"{} {}\">", desc_desc, use_desc)?;
write!(output, "<div class=\"{}\">", desc_desc)?;
// Error title (with self-link).
write!(output,
@ -199,25 +199,6 @@ impl Formatter for MarkdownFormatter {
}
}
/// Loads all the metadata files from `metadata_dir` into an in-memory map.
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<dyn Error>> {
let mut all_errors = BTreeMap::new();
for entry in read_dir(metadata_dir)? {
let path = entry?.path();
let metadata_str = fs::read_to_string(&path)?;
let some_errors: ErrorMetadataMap = json::decode(&metadata_str)?;
for (err_code, info) in some_errors {
all_errors.insert(err_code, info);
}
}
Ok(all_errors)
}
/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
formatter: T) -> Result<(), Box<dyn Error>> {
@ -234,9 +215,13 @@ fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Pat
}
fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
let build_arch = env::var("CFG_BUILD")?;
let metadata_dir = get_metadata_dir(&build_arch);
let err_map = load_all_errors(&metadata_dir)?;
let long_codes = register_all();
let mut err_map = BTreeMap::new();
for (code, desc) in long_codes {
err_map.insert(code.to_string(), ErrorMetadata {
description: desc.map(String::from),
});
}
match format {
OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
@ -272,3 +257,5 @@ fn main() {
panic!("{}", e.description());
}
}
include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));