makepad/libs/relax/lex/tests/validate.rs
Admin ad03c2f488 makepad run / Relax: library stability, attribute shapes, more lints, x64 TLS fix
- stability: unstable std/core/alloc items need their feature (E0658) on every
  path, from a table generated from rustc's library sources (std/gen_stability.py)
- attributes: malformed `inline`/`must_use`/`deprecated`/`link*` (E0539/E0805/
  E0565) and other attribute-shape checks; `main` entry checks
- typeck: ManuallyDrop is a transparent lang-item struct (dyn unsizing through
  it works); invalid assignment targets (E0070/E0067); wide_pointer_comparisons
- consts: generic param order/defaults, const param types, E0572, cycles; NaN
  and non-structural constants in patterns; E0491/E0478 well-formedness
- parser: cfg paren-expr meta, `$t:ty` not a bound, items in impl/trait bodies
- lints: unused_imports from recorded import use; unused_mut through closures,
  non_shorthand_field_patterns, drop_bounds, dyn_drop and more
- codegen: x64 domain-base TLS read no longer skips its block (segfault fixed);
  arm64 constant-size copies of 32 B+ as 16-byte vector pairs
- rustc tests/ui agreement ~93.4%

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:20:42 +02:00

63 lines
3.7 KiB
Rust

//! Literal validation of the Rust scanner (rustc_parse `cook_lexer_literal`, rustc_literal_escaper).
use relax_lex::lexer::lex;
fn err(src: &str, edition: u16) -> Option<String> {
relax_lex::lexer::set_validation(true);
let mut toks = Vec::new();
lex(src.as_bytes(), edition, &mut toks).map_err(|e| e.msg.into_owned()).and_then(|_| relax_lex::lexer::validate_file(src.as_bytes(), &toks, edition).map_err(|e| e.msg.into_owned())).err()
}
#[test]
fn valid_literals_pass() {
for s in [
r#"let a = "a\n\t\\\"\'\0\x41\u{1F600}\u{00_41}";"#, "let b = b'\\xff'; let c = b\"\\xff\";", "let d = c\"\\xff\";",
"let e = 0b1010_u8; let f = 0o777; let g = 0xdead_beefu64; let h = 1_000.5e-3_f64; let i = 1e10;",
"let j = r#\"raw \\ \"# ; let k = '\\''; let l = 'a'; let m = \"line \\\n continues\";",
"let r#abstract = 1; let ñandú = 2; let 变量 = 3;", "let n = 340282366920938463463374607431768211455u128;",
] {
assert_eq!(err(s, 2021), None, "{s}");
}
}
#[test]
fn bad_escapes_and_digits_are_errors() {
assert!(err("let a = \"\\q\";", 2021).unwrap().contains("unknown character escape"));
assert!(err("let a = b\"\\q\";", 2021).unwrap().contains("unknown byte escape"));
assert!(err("let a = \"\\xff\";", 2021).unwrap().contains("out of range hex escape"));
assert!(err("let a = '\\x4';", 2021).unwrap().contains("too short"));
assert!(err("let a = \"\\u{110000}\";", 2021).unwrap().contains("invalid unicode character escape"));
assert!(err("let a = b\"\\u{41}\";", 2021).unwrap().contains("unicode escape in byte string"));
assert!(err("let a = \"\\u{1234567}\";", 2021).unwrap().contains("overlong"));
assert!(err("let a = 0b12;", 2021).unwrap().contains("invalid digit for a base 2 literal"));
assert!(err("let a = 0o8;", 2021).unwrap().contains("invalid digit for a base 8 literal"));
assert!(err("let a = 0x;", 2021).unwrap().contains("no valid digits"));
assert!(err("let a = 1e;", 2021).unwrap().contains("exponent"));
assert!(err("let a = 1is;", 2021).unwrap().contains("invalid suffix"));
assert!(err("let a = 340282366920938463463374607431768211456;", 2021).unwrap().contains("too large"));
assert!(err("let a = \"x\"y;", 2021).unwrap().contains("suffixes on string literals"));
assert!(err("let a = \"x\"_;", 2021).unwrap().contains("underscore literal suffix"));
assert!(err("let a = r#self;", 2021).unwrap().contains("raw identifier"));
assert!(err("let a = b\"é\";", 2021).unwrap().contains("non-ASCII"));
assert!(err("let 🦀 = 1;", 2021).unwrap().contains("Ferris"));
assert!(err("let a = f\"x\";", 2021).unwrap().contains("is unknown"));
assert_eq!(err("let a = f\"x\";", 2018), None);
}
#[test]
fn literals_in_macro_token_trees_are_not_cooked_by_the_parser_checks() {
// rustc judges a literal's suffix and size when the parser consumes it, never inside a macro
// invocation's tokens (Splash colours: `#1a1b26`); the lexer's own errors still apply there
for s in ["m!{ x: #1a1b26 }", "m!(1x, \"a\"b, 'c'd, 340282366920938463463374607431768211456)", "macro_rules! m { () => { 1x } }", "#[a(1x)] fn f() {}"] {
assert_eq!(err(s, 2021), None, "{s}");
}
assert!(err("let a = 1x;", 2021).unwrap().contains("invalid suffix"));
assert!(err("m!{ 0b102 }", 2021).unwrap().contains("invalid digit for a base 2 literal"));
assert!(err("m!{ \"\\q\" }", 2021).unwrap().contains("unknown character escape"));
}
#[test]
fn std_macros_that_parse_expressions_cook_their_literals() {
assert!(err("fn main() { println!(\"\"y); }", 2021).unwrap().contains("suffixes on string literals"));
assert!(err("fn main() { let v = vec![1x]; }", 2021).unwrap().contains("invalid suffix"));
assert_eq!(err("fn main() { m!(1x); }", 2021), None);
}