diff --git a/time-macros/src/format_description/ast.rs b/time-macros/src/format_description/ast.rs index 5ac201ac1..497c8965d 100644 --- a/time-macros/src/format_description/ast.rs +++ b/time-macros/src/format_description/ast.rs @@ -81,7 +81,7 @@ fn parse_inner< Some(match next { lexer::Token::Literal(Spanned { value: _, span: _ }) if NESTED => { - unreachable!("internal error: literal should not be present in nested description") + bug!("literal should not be present in nested description") } lexer::Token::Literal(value) => Ok(Item::Literal(value)), lexer::Token::Bracket { @@ -105,23 +105,18 @@ fn parse_inner< kind: lexer::BracketKind::Closing, location: _, } if NESTED => { - unreachable!( - "internal error: closing bracket should be caught by the `if` statement" - ) + bug!("closing bracket should be caught by the `if` statement") } lexer::Token::Bracket { kind: lexer::BracketKind::Closing, location: _, } => { - unreachable!( - "internal error: closing bracket should have been consumed by \ - `parse_component`" - ) + bug!("closing bracket should have been consumed by `parse_component`") } lexer::Token::ComponentPart { kind: _, value } if NESTED => Ok(Item::Literal(value)), - lexer::Token::ComponentPart { kind: _, value: _ } => unreachable!( - "internal error: component part should have been consumed by `parse_component`" - ), + lexer::Token::ComponentPart { kind: _, value: _ } => { + bug!("component part should have been consumed by `parse_component`") + } }) }) } diff --git a/time-macros/src/format_description/format_item.rs b/time-macros/src/format_description/format_item.rs index c94a04431..46c277d2f 100644 --- a/time-macros/src/format_description/format_item.rs +++ b/time-macros/src/format_description/format_item.rs @@ -107,7 +107,7 @@ impl<'a> From<Box<[Item<'a>]>> for crate::format_description::public::OwnedForma if let Ok([item]) = <[_; 1]>::try_from(items) { item.into() } else { - unreachable!("the length was just checked to be 1") + bug!("the length was just checked to be 1") } } else { Self::Compound(items.into_iter().map(Self::from).collect()) @@ -181,9 +181,7 @@ macro_rules! component_definition { then { match $field { Some(value) => value.into(), - None => unreachable!( - "internal error: required modifier was not set" - ), + None => bug!("required modifier was not set"), } } else { $field.unwrap_or_default().into() diff --git a/time-macros/src/helpers/string.rs b/time-macros/src/helpers/string.rs index fa3780f5e..6b478f60d 100644 --- a/time-macros/src/helpers/string.rs +++ b/time-macros/src/helpers/string.rs @@ -57,7 +57,7 @@ fn parse_lit_str_cooked(mut s: &str) -> Vec<u8> { continue 'outer; } }, - _ => unreachable!("invalid escape"), + _ => bug!("invalid escape"), } } b'\r' => { @@ -120,7 +120,7 @@ fn parse_lit_byte_str_cooked(mut v: &[u8]) -> Vec<u8> { continue 'outer; } }, - _ => unreachable!("invalid escape"), + _ => bug!("invalid escape"), } } b'\r' => { @@ -151,7 +151,7 @@ where b'0'..=b'9' => b1 - b'0', b'a'..=b'f' => 10 + (b1 - b'a'), b'A'..=b'F' => 10 + (b1 - b'A'), - _ => unreachable!("invalid hex escape"), + _ => bug!("invalid hex escape"), }; (ch, &s[2..]) } @@ -172,7 +172,7 @@ fn backslash_u(mut s: &str) -> (char, &str) { continue; } b'}' if digits != 0 => break, - _ => unreachable!("invalid unicode escape"), + _ => bug!("invalid unicode escape"), }; ch *= 0x10; ch += u32::from(digit); diff --git a/time-macros/src/lib.rs b/time-macros/src/lib.rs index 9d7ccb889..84ad25113 100644 --- a/time-macros/src/lib.rs +++ b/time-macros/src/lib.rs @@ -33,6 +33,13 @@ clippy::option_if_let_else, // suggests terrible code )] +macro_rules! bug { + () => { compile_error!("provide an error message to help fix a possible bug") }; + ($descr:literal $($rest:tt)?) => { + unreachable!(concat!("internal error: ", $descr) $($rest)?) + } +} + #[macro_use] mod quote; #[cfg(any(feature = "formatting", feature = "parsing"))] @@ -165,7 +172,7 @@ pub fn format_description(input: TokenStream) -> TokenStream { Some(VersionOrModuleName::Version(version)) => Some(version), None => None, // This branch should never occur here, as `false` is the provided as a const parameter. - Some(VersionOrModuleName::ModuleName(_)) => unreachable!(), + Some(VersionOrModuleName::ModuleName(_)) => bug!("branch should never occur"), }; let (span, string) = helpers::get_string_literal(input)?; let items = format_description::parse_with_version(version, &string, span)?; diff --git a/time/src/format_description/parse/ast.rs b/time/src/format_description/parse/ast.rs index 0af4e0bde..f7b0ab78c 100644 --- a/time/src/format_description/parse/ast.rs +++ b/time/src/format_description/parse/ast.rs @@ -129,7 +129,7 @@ fn parse_inner< Some(match next { lexer::Token::Literal(Spanned { value: _, span: _ }) if NESTED => { - unreachable!("internal error: literal should not be present in nested description") + bug!("literal should not be present in nested description") } lexer::Token::Literal(value) => Ok(Item::Literal(value)), lexer::Token::Bracket { @@ -153,26 +153,21 @@ fn parse_inner< kind: lexer::BracketKind::Closing, location: _, } if NESTED => { - unreachable!( - "internal error: closing bracket should be caught by the `if` statement" - ) + bug!("closing bracket should be caught by the `if` statement") } lexer::Token::Bracket { kind: lexer::BracketKind::Closing, location: _, } => { - unreachable!( - "internal error: closing bracket should have been consumed by \ - `parse_component`" - ) + bug!("closing bracket should have been consumed by `parse_component`") } lexer::Token::ComponentPart { kind: _, // whitespace is significant in nested components value, } if NESTED => Ok(Item::Literal(value)), - lexer::Token::ComponentPart { kind: _, value: _ } => unreachable!( - "internal error: component part should have been consumed by `parse_component`" - ), + lexer::Token::ComponentPart { kind: _, value: _ } => { + bug!("component part should have been consumed by `parse_component`") + } }) }) } diff --git a/time/src/format_description/parse/format_item.rs b/time/src/format_description/parse/format_item.rs index b65e211e0..582bfbbce 100644 --- a/time/src/format_description/parse/format_item.rs +++ b/time/src/format_description/parse/format_item.rs @@ -152,7 +152,7 @@ impl<'a> From<Box<[Item<'a>]>> for crate::format_description::OwnedFormatItem { if let Ok([item]) = <[_; 1]>::try_from(items) { item.into() } else { - unreachable!("the length was just checked to be 1") + bug!("the length was just checked to be 1") } } else { Self::Compound(items.into_iter().map(Self::from).collect()) @@ -241,9 +241,7 @@ macro_rules! component_definition { then { match $field { Some(value) => value.into(), - None => unreachable!( - "internal error: required modifier was not set" - ), + None => bug!("required modifier was not set"), } } else { $field.unwrap_or_default().into() diff --git a/time/src/lib.rs b/time/src/lib.rs index e0f439377..5ebcf83a1 100644 --- a/time/src/lib.rs +++ b/time/src/lib.rs @@ -300,6 +300,14 @@ macro_rules! expect_opt { } }; } + +/// `unreachable!()`, but better. +macro_rules! bug { + () => { compile_error!("provide an error message to help fix a possible bug") }; + ($descr:literal $($rest:tt)?) => { + unreachable!(concat!("internal error: ", $descr) $($rest)?) + } +} // endregion macros #[macro_use] diff --git a/time/src/parsing/parsable.rs b/time/src/parsing/parsable.rs index cd2f2723d..c519dc36f 100644 --- a/time/src/parsing/parsable.rs +++ b/time/src/parsing/parsable.rs @@ -750,7 +750,7 @@ impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> { if !date_is_present && !time_is_present && !offset_is_present { match first_error { Some(err) => return Err(err), - None => unreachable!("an error should be present if no components were parsed"), + None => bug!("an error should be present if no components were parsed"), } }