1 use errors
::{Applicability, DiagnosticBuilder}
;
3 use rustc_parse
::parser
::Parser
;
4 use syntax
::ast
::{self, *}
;
5 use syntax
::token
::{self, TokenKind}
;
6 use syntax
::print
::pprust
;
8 use syntax
::symbol
::{sym, Symbol}
;
9 use syntax
::tokenstream
::{DelimSpan, TokenStream, TokenTree}
;
10 use syntax_expand
::base
::*;
11 use syntax_pos
::{Span, DUMMY_SP}
;
13 pub fn expand_assert
<'cx
>(
14 cx
: &'cx
mut ExtCtxt
<'_
>,
17 ) -> Box
<dyn MacResult
+ 'cx
> {
18 let Assert { cond_expr, custom_message }
= match parse_assert(cx
, sp
, tts
) {
22 return DummyResult
::any(sp
);
26 // `core::panic` and `std::panic` are different macros, so we use call-site
27 // context to pick up whichever is currently in scope.
28 let sp
= cx
.with_call_site_ctxt(sp
);
29 let tokens
= custom_message
.unwrap_or_else(|| {
30 TokenStream
::from(TokenTree
::token(
31 TokenKind
::lit(token
::Str
, Symbol
::intern(&format
!(
32 "assertion failed: {}",
33 pprust
::expr_to_string(&cond_expr
).escape_debug()
38 let args
= P(MacArgs
::Delimited(DelimSpan
::from_single(sp
), MacDelimiter
::Parenthesis
, tokens
));
39 let panic_call
= Mac
{
40 path
: Path
::from_ident(Ident
::new(sym
::panic
, sp
)),
42 prior_type_ascription
: None
,
44 let if_expr
= cx
.expr_if(
46 cx
.expr(sp
, ExprKind
::Unary(UnOp
::Not
, cond_expr
)),
49 ExprKind
::Mac(panic_call
),
53 MacEager
::expr(if_expr
)
57 cond_expr
: P
<ast
::Expr
>,
58 custom_message
: Option
<TokenStream
>,
65 ) -> Result
<Assert
, DiagnosticBuilder
<'a
>> {
66 let mut parser
= cx
.new_parser_from_tts(stream
);
68 if parser
.token
== token
::Eof
{
69 let mut err
= cx
.struct_span_err(sp
, "macro requires a boolean expression as an argument");
70 err
.span_label(sp
, "boolean expression required");
74 let cond_expr
= parser
.parse_expr()?
;
76 // Some crates use the `assert!` macro in the following form (note extra semicolon):
82 // Warn about semicolon and suggest removing it. Eventually, this should be turned into an
84 if parser
.token
== token
::Semi
{
85 let mut err
= cx
.struct_span_warn(sp
, "macro requires an expression as an argument");
88 "try removing semicolon",
90 Applicability
::MaybeIncorrect
92 err
.note("this is going to be an error in the future");
98 // Some crates use the `assert!` macro in the following form (note missing comma before
101 // assert!(true "error message");
103 // Parse this as an actual message, and suggest inserting a comma. Eventually, this should be
104 // turned into an error.
105 let custom_message
= if let token
::Literal(token
::Lit { kind: token::Str, .. }
)
106 = parser
.token
.kind
{
107 let mut err
= cx
.struct_span_warn(parser
.token
.span
, "unexpected string literal");
108 let comma_span
= parser
.prev_span
.shrink_to_hi();
109 err
.span_suggestion_short(
111 "try adding a comma",
113 Applicability
::MaybeIncorrect
115 err
.note("this is going to be an error in the future");
118 parse_custom_message(&mut parser
)
119 } else if parser
.eat(&token
::Comma
) {
120 parse_custom_message(&mut parser
)
125 if parser
.token
!= token
::Eof
{
126 parser
.expect_one_of(&[], &[])?
;
130 Ok(Assert { cond_expr, custom_message }
)
133 fn parse_custom_message(parser
: &mut Parser
<'_
>) -> Option
<TokenStream
> {
134 let ts
= parser
.parse_tokens();