1
Fork 0

Use token::Lit in ast::ExprKind::Lit.

Instead of `ast::Lit`.

Literal lowering now happens at two different times. Expression literals
are lowered when HIR is crated. Attribute literals are lowered during
parsing.

This commit changes the language very slightly. Some programs that used
to not compile now will compile. This is because some invalid literals
that are removed by `cfg` or attribute macros will no longer trigger
errors. See this comment for more details:
https://github.com/rust-lang/rust/pull/102944#issuecomment-1277476773
This commit is contained in:
Nicholas Nethercote 2022-10-10 13:40:56 +11:00
parent 01760265cb
commit 358a603f11
45 changed files with 701 additions and 581 deletions

View file

@ -172,7 +172,11 @@ pub fn parse_asm_args<'a>(
// If it can't possibly expand to a string, provide diagnostics here to include other
// things it could have been.
match template.kind {
ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
ast::ExprKind::Lit(token_lit)
if matches!(
token_lit.kind,
token::LitKind::Str | token::LitKind::StrRaw(_)
) => {}
ast::ExprKind::MacCall(..) => {}
_ => {
let errstr = if is_global_asm {

View file

@ -1,6 +1,7 @@
use rustc_ast as ast;
use rustc_ast::tokenstream::TokenStream;
use rustc_expand::base::{self, DummyResult};
use rustc_session::errors::report_lit_error;
use rustc_span::symbol::Symbol;
use std::string::String;
@ -18,28 +19,28 @@ pub fn expand_concat(
let mut has_errors = false;
for e in es {
match e.kind {
ast::ExprKind::Lit(ref lit) => match lit.kind {
ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _) => {
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _)) => {
accumulator.push_str(s.as_str());
}
ast::LitKind::Char(c) => {
Ok(ast::LitKind::Char(c)) => {
accumulator.push(c);
}
ast::LitKind::Int(
i,
ast::LitIntType::Unsigned(_)
| ast::LitIntType::Signed(_)
| ast::LitIntType::Unsuffixed,
) => {
Ok(ast::LitKind::Int(i, _)) => {
accumulator.push_str(&i.to_string());
}
ast::LitKind::Bool(b) => {
Ok(ast::LitKind::Bool(b)) => {
accumulator.push_str(&b.to_string());
}
ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => {
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
cx.span_err(e.span, "cannot concatenate a byte string literal");
has_errors = true;
}
ast::LitKind::Err => {
Ok(ast::LitKind::Err) => {
has_errors = true;
}
Err(err) => {
report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span);
has_errors = true;
}
},

View file

@ -2,18 +2,21 @@ use rustc_ast as ast;
use rustc_ast::{ptr::P, tokenstream::TokenStream};
use rustc_errors::Applicability;
use rustc_expand::base::{self, DummyResult};
use rustc_span::Span;
/// Emits errors for literal expressions that are invalid inside and outside of an array.
fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_nested: bool) {
let ast::ExprKind::Lit(lit) = &expr.kind else {
unreachable!();
};
match lit.kind {
ast::LitKind::Char(_) => {
let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals");
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
fn invalid_type_err(
cx: &mut base::ExtCtxt<'_>,
token_lit: ast::token::Lit,
span: Span,
is_nested: bool,
) {
match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Char(_)) => {
let mut err = cx.struct_span_err(span, "cannot concatenate character literals");
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
err.span_suggestion(
expr.span,
span,
"try using a byte character",
format!("b{}", snippet),
Applicability::MachineApplicable,
@ -21,13 +24,13 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
.emit();
}
}
ast::LitKind::Str(_, _) => {
let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals");
Ok(ast::LitKind::Str(_, _)) => {
let mut err = cx.struct_span_err(span, "cannot concatenate string literals");
// suggestion would be invalid if we are nested
if !is_nested {
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
err.span_suggestion(
expr.span,
span,
"try using a byte string",
format!("b{}", snippet),
Applicability::MachineApplicable,
@ -36,18 +39,18 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
}
err.emit();
}
ast::LitKind::Float(_, _) => {
cx.span_err(expr.span, "cannot concatenate float literals");
Ok(ast::LitKind::Float(_, _)) => {
cx.span_err(span, "cannot concatenate float literals");
}
ast::LitKind::Bool(_) => {
cx.span_err(expr.span, "cannot concatenate boolean literals");
Ok(ast::LitKind::Bool(_)) => {
cx.span_err(span, "cannot concatenate boolean literals");
}
ast::LitKind::Err => {}
ast::LitKind::Int(_, _) if !is_nested => {
let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
Ok(ast::LitKind::Err) => {}
Ok(ast::LitKind::Int(_, _)) if !is_nested => {
let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals");
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
err.span_suggestion(
expr.span,
span,
"try wrapping the number in an array",
format!("[{}]", snippet),
Applicability::MachineApplicable,
@ -55,15 +58,15 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
}
err.emit();
}
ast::LitKind::Int(
Ok(ast::LitKind::Int(
val,
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
) => {
)) => {
assert!(val > u8::MAX.into()); // must be an error
cx.span_err(expr.span, "numeric literal is out of bounds");
cx.span_err(span, "numeric literal is out of bounds");
}
ast::LitKind::Int(_, _) => {
cx.span_err(expr.span, "numeric literal is not a `u8`");
Ok(ast::LitKind::Int(_, _)) => {
cx.span_err(span, "numeric literal is not a `u8`");
}
_ => unreachable!(),
}
@ -83,14 +86,14 @@ fn handle_array_element(
*has_errors = true;
None
}
ast::ExprKind::Lit(ref lit) => match lit.kind {
ast::LitKind::Int(
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Int(
val,
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
) if val <= u8::MAX.into() => Some(val as u8),
)) if val <= u8::MAX.into() => Some(val as u8),
ast::LitKind::Byte(val) => Some(val),
ast::LitKind::ByteStr(_) => {
Ok(ast::LitKind::Byte(val)) => Some(val),
Ok(ast::LitKind::ByteStr(_)) => {
if !*has_errors {
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
.note("byte strings are treated as arrays of bytes")
@ -102,7 +105,7 @@ fn handle_array_element(
}
_ => {
if !*has_errors {
invalid_type_err(cx, expr, true);
invalid_type_err(cx, token_lit, expr.span, true);
}
*has_errors = true;
None
@ -148,9 +151,9 @@ pub fn expand_concat_bytes(
}
}
ast::ExprKind::Repeat(ref expr, ref count) => {
if let ast::ExprKind::Lit(ast::Lit {
kind: ast::LitKind::Int(count_val, _), ..
}) = count.value.kind
if let ast::ExprKind::Lit(token_lit) = count.value.kind
&& let Ok(ast::LitKind::Int(count_val, _)) =
ast::LitKind::from_token_lit(token_lit)
{
if let Some(elem) =
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
@ -163,16 +166,16 @@ pub fn expand_concat_bytes(
cx.span_err(count.value.span, "repeat count is not a positive number");
}
}
ast::ExprKind::Lit(ref lit) => match lit.kind {
ast::LitKind::Byte(val) => {
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Byte(val)) => {
accumulator.push(val);
}
ast::LitKind::ByteStr(ref bytes) => {
Ok(ast::LitKind::ByteStr(ref bytes)) => {
accumulator.extend_from_slice(&bytes);
}
_ => {
if !has_errors {
invalid_type_err(cx, &e, false);
invalid_type_err(cx, token_lit, e.span, false);
}
has_errors = true;
}