mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
diag(wgsl-in): use backticks for code-like text in WGSL FE errors (#6908)
This commit is contained in:
@@ -359,22 +359,22 @@ impl<'a> Error<'a> {
|
||||
Error::Unexpected(unexpected_span, expected) => {
|
||||
let expected_str = match expected {
|
||||
ExpectedToken::Token(token) => match token {
|
||||
Token::Separator(c) => format!("'{c}'"),
|
||||
Token::Paren(c) => format!("'{c}'"),
|
||||
Token::Separator(c) => format!("`{c}`"),
|
||||
Token::Paren(c) => format!("`{c}`"),
|
||||
Token::Attribute => "@".to_string(),
|
||||
Token::Number(_) => "number".to_string(),
|
||||
Token::Word(s) => s.to_string(),
|
||||
Token::Operation(c) => format!("operation ('{c}')"),
|
||||
Token::LogicalOperation(c) => format!("logical operation ('{c}')"),
|
||||
Token::ShiftOperation(c) => format!("bitshift ('{c}{c}')"),
|
||||
Token::Operation(c) => format!("operation (`{c}`)"),
|
||||
Token::LogicalOperation(c) => format!("logical operation (`{c}`)"),
|
||||
Token::ShiftOperation(c) => format!("bitshift (`{c}{c}`)"),
|
||||
Token::AssignmentOperation(c) if c == '<' || c == '>' => {
|
||||
format!("bitshift ('{c}{c}=')")
|
||||
format!("bitshift (`{c}{c}=`)")
|
||||
}
|
||||
Token::AssignmentOperation(c) => format!("operation ('{c}=')"),
|
||||
Token::AssignmentOperation(c) => format!("operation (`{c}=`)"),
|
||||
Token::IncrementOperation => "increment operation".to_string(),
|
||||
Token::DecrementOperation => "decrement operation".to_string(),
|
||||
Token::Arrow => "->".to_string(),
|
||||
Token::Unknown(c) => format!("unknown ('{c}')"),
|
||||
Token::Unknown(c) => format!("unknown (`{c}`)"),
|
||||
Token::Trivia => "trivia".to_string(),
|
||||
Token::End => "end".to_string(),
|
||||
},
|
||||
@@ -382,15 +382,15 @@ impl<'a> Error<'a> {
|
||||
ExpectedToken::PrimaryExpression => "expression".to_string(),
|
||||
ExpectedToken::Assignment => "assignment or increment/decrement".to_string(),
|
||||
ExpectedToken::SwitchItem => concat!(
|
||||
"switch item ('case' or 'default') or a closing curly bracket ",
|
||||
"to signify the end of the switch statement ('}')"
|
||||
"switch item (`case` or `default`) or a closing curly bracket ",
|
||||
"to signify the end of the switch statement (`}`)"
|
||||
)
|
||||
.to_string(),
|
||||
ExpectedToken::WorkgroupSizeSeparator => {
|
||||
"workgroup size separator (',') or a closing parenthesis".to_string()
|
||||
"workgroup size separator (`,`) or a closing parenthesis".to_string()
|
||||
}
|
||||
ExpectedToken::GlobalItem => concat!(
|
||||
"global item ('struct', 'const', 'var', 'alias', 'fn', 'diagnostic', 'enable', 'requires', ';') ",
|
||||
"global item (`struct`, `const`, `var`, `alias`, `fn`, `diagnostic`, `enable`, `requires`, `;`) ",
|
||||
"or the end of the file"
|
||||
)
|
||||
.to_string(),
|
||||
@@ -398,13 +398,13 @@ impl<'a> Error<'a> {
|
||||
ExpectedToken::Variable => "variable access".to_string(),
|
||||
ExpectedToken::Function => "function name".to_string(),
|
||||
ExpectedToken::AfterIdentListArg => {
|
||||
"next argument, trailing comma, or end of list (',' or ';')".to_string()
|
||||
"next argument, trailing comma, or end of list (`,` or `;`)".to_string()
|
||||
}
|
||||
ExpectedToken::AfterIdentListComma => {
|
||||
"next argument or end of list (';')".to_string()
|
||||
"next argument or end of list (`;`)".to_string()
|
||||
}
|
||||
ExpectedToken::DiagnosticAttribute => {
|
||||
"the 'diagnostic' attribute identifier".to_string()
|
||||
"the `diagnostic` attribute identifier".to_string()
|
||||
}
|
||||
};
|
||||
ParseError {
|
||||
@@ -445,12 +445,12 @@ impl<'a> Error<'a> {
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownIdent(ident_span, ident) => ParseError {
|
||||
message: format!("no definition in scope for identifier: '{ident}'"),
|
||||
message: format!("no definition in scope for identifier: `{ident}`"),
|
||||
labels: vec![(ident_span, "unknown identifier".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownScalarType(bad_span) => ParseError {
|
||||
message: format!("unknown scalar type: '{}'", &source[bad_span]),
|
||||
message: format!("unknown scalar type: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown scalar type".into())],
|
||||
notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()],
|
||||
},
|
||||
@@ -473,7 +473,7 @@ impl<'a> Error<'a> {
|
||||
},
|
||||
Error::BadTexture(bad_span) => ParseError {
|
||||
message: format!(
|
||||
"expected an image, but found '{}' which is not an image",
|
||||
"expected an image, but found `{}` which is not an image",
|
||||
&source[bad_span]
|
||||
),
|
||||
labels: vec![(bad_span, "not an image".into())],
|
||||
@@ -498,7 +498,7 @@ impl<'a> Error<'a> {
|
||||
},
|
||||
Error::InvalidForInitializer(bad_span) => ParseError {
|
||||
message: format!(
|
||||
"for(;;) initializer is not an assignment or a function call: '{}'",
|
||||
"for(;;) initializer is not an assignment or a function call: `{}`",
|
||||
&source[bad_span]
|
||||
),
|
||||
labels: vec![(bad_span, "not an assignment or function call".into())],
|
||||
@@ -511,7 +511,7 @@ impl<'a> Error<'a> {
|
||||
},
|
||||
Error::InvalidGatherComponent(bad_span) => ParseError {
|
||||
message: format!(
|
||||
"textureGather component '{}' doesn't exist, must be 0, 1, 2, or 3",
|
||||
"textureGather component `{}` doesn't exist, must be 0, 1, 2, or 3",
|
||||
&source[bad_span]
|
||||
),
|
||||
labels: vec![(bad_span, "invalid component".into())],
|
||||
@@ -523,58 +523,58 @@ impl<'a> Error<'a> {
|
||||
notes: vec![],
|
||||
},
|
||||
Error::InvalidIdentifierUnderscore(bad_span) => ParseError {
|
||||
message: "Identifier can't be '_'".to_string(),
|
||||
message: "Identifier can't be `_`".to_string(),
|
||||
labels: vec![(bad_span, "invalid identifier".into())],
|
||||
notes: vec![
|
||||
"Use phony assignment instead ('_ =' notice the absence of 'let' or 'var')"
|
||||
"Use phony assignment instead (`_ =` notice the absence of `let` or `var`)"
|
||||
.to_string(),
|
||||
],
|
||||
},
|
||||
Error::ReservedIdentifierPrefix(bad_span) => ParseError {
|
||||
message: format!(
|
||||
"Identifier starts with a reserved prefix: '{}'",
|
||||
"Identifier starts with a reserved prefix: `{}`",
|
||||
&source[bad_span]
|
||||
),
|
||||
labels: vec![(bad_span, "invalid identifier".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownAddressSpace(bad_span) => ParseError {
|
||||
message: format!("unknown address space: '{}'", &source[bad_span]),
|
||||
message: format!("unknown address space: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown address space".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::RepeatedAttribute(bad_span) => ParseError {
|
||||
message: format!("repeated attribute: '{}'", &source[bad_span]),
|
||||
message: format!("repeated attribute: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "repeated attribute".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownAttribute(bad_span) => ParseError {
|
||||
message: format!("unknown attribute: '{}'", &source[bad_span]),
|
||||
message: format!("unknown attribute: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown attribute".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownBuiltin(bad_span) => ParseError {
|
||||
message: format!("unknown builtin: '{}'", &source[bad_span]),
|
||||
message: format!("unknown builtin: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown builtin".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownAccess(bad_span) => ParseError {
|
||||
message: format!("unknown access: '{}'", &source[bad_span]),
|
||||
message: format!("unknown access: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown access".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownStorageFormat(bad_span) => ParseError {
|
||||
message: format!("unknown storage format: '{}'", &source[bad_span]),
|
||||
message: format!("unknown storage format: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown storage format".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownConservativeDepth(bad_span) => ParseError {
|
||||
message: format!("unknown conservative depth: '{}'", &source[bad_span]),
|
||||
message: format!("unknown conservative depth: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown conservative depth".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::UnknownType(bad_span) => ParseError {
|
||||
message: format!("unknown type: '{}'", &source[bad_span]),
|
||||
message: format!("unknown type: `{}`", &source[bad_span]),
|
||||
labels: vec![(bad_span, "unknown type".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
@@ -702,7 +702,7 @@ impl<'a> Error<'a> {
|
||||
InvalidAssignmentType::ImmutableBinding(binding_span) => (
|
||||
Some((binding_span, "this is an immutable binding".into())),
|
||||
vec![format!(
|
||||
"consider declaring '{}' with `var` instead of `let`",
|
||||
"consider declaring `{}` with `var` instead of `let`",
|
||||
&source[binding_span]
|
||||
)],
|
||||
),
|
||||
@@ -782,11 +782,11 @@ impl<'a> Error<'a> {
|
||||
.into(),
|
||||
)],
|
||||
notes: vec![if uint {
|
||||
format!("suffix the integer with a `u`: '{}u'", &source[span])
|
||||
format!("suffix the integer with a `u`: `{}u`", &source[span])
|
||||
} else {
|
||||
let span = span.to_range().unwrap();
|
||||
format!(
|
||||
"remove the `u` suffix: '{}'",
|
||||
"remove the `u` suffix: `{}`",
|
||||
&source[span.start..span.end - 1]
|
||||
)
|
||||
}],
|
||||
@@ -833,10 +833,10 @@ impl<'a> Error<'a> {
|
||||
Error::ExpectedConstExprConcreteIntegerScalar(span) => ParseError {
|
||||
message: concat!(
|
||||
"must be a const-expression that ",
|
||||
"resolves to a concrete integer scalar (u32 or i32)"
|
||||
"resolves to a concrete integer scalar (`u32` or `i32`)"
|
||||
)
|
||||
.to_string(),
|
||||
labels: vec![(span, "must resolve to u32 or i32".into())],
|
||||
labels: vec![(span, "must resolve to `u32` or `i32`".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::ExpectedNonNegative(span) => ParseError {
|
||||
@@ -858,7 +858,7 @@ impl<'a> Error<'a> {
|
||||
message: "workgroup size is missing on compute shader entry point".to_string(),
|
||||
labels: vec![(
|
||||
span,
|
||||
"must be paired with a @workgroup_size attribute".into(),
|
||||
"must be paired with a `@workgroup_size` attribute".into(),
|
||||
)],
|
||||
notes: vec![],
|
||||
},
|
||||
@@ -947,13 +947,13 @@ impl<'a> Error<'a> {
|
||||
notes: vec![],
|
||||
},
|
||||
Error::NotBool(span) => ParseError {
|
||||
message: "must be a const-expression that resolves to a bool".to_string(),
|
||||
labels: vec![(span, "must resolve to bool".into())],
|
||||
message: "must be a const-expression that resolves to a `bool`".to_string(),
|
||||
labels: vec![(span, "must resolve to `bool`".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::ConstAssertFailed(span) => ParseError {
|
||||
message: "const_assert failure".to_string(),
|
||||
labels: vec![(span, "evaluates to false".into())],
|
||||
message: "`const_assert` failure".to_string(),
|
||||
labels: vec![(span, "evaluates to `false`".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::DirectiveAfterFirstGlobalDecl { directive_span } => ParseError {
|
||||
|
||||
@@ -38,7 +38,7 @@ fn very_negative_integers() {
|
||||
fn reserved_identifier_prefix() {
|
||||
check(
|
||||
"var __bad;",
|
||||
r###"error: Identifier starts with a reserved prefix: '__bad'
|
||||
r###"error: Identifier starts with a reserved prefix: `__bad`
|
||||
┌─ wgsl:1:5
|
||||
│
|
||||
1 │ var __bad;
|
||||
@@ -112,7 +112,7 @@ fn unknown_identifier() {
|
||||
return x * schmoo;
|
||||
}
|
||||
"###,
|
||||
r###"error: no definition in scope for identifier: 'schmoo'
|
||||
r###"error: no definition in scope for identifier: `schmoo`
|
||||
┌─ wgsl:3:30
|
||||
│
|
||||
3 │ return x * schmoo;
|
||||
@@ -134,7 +134,7 @@ fn bad_texture() {
|
||||
return textureSample(a, sampler1, vec2<f32>(0.0));
|
||||
}
|
||||
"#,
|
||||
r#"error: expected an image, but found 'a' which is not an image
|
||||
r#"error: expected an image, but found `a` which is not an image
|
||||
┌─ wgsl:7:38
|
||||
│
|
||||
7 │ return textureSample(a, sampler1, vec2<f32>(0.0));
|
||||
@@ -266,7 +266,7 @@ fn bad_for_initializer() {
|
||||
for ({};;) {}
|
||||
}
|
||||
"#,
|
||||
r#"error: for(;;) initializer is not an assignment or a function call: '{}'
|
||||
r#"error: for(;;) initializer is not an assignment or a function call: `{}`
|
||||
┌─ wgsl:3:22
|
||||
│
|
||||
3 │ for ({};;) {}
|
||||
@@ -282,7 +282,7 @@ fn unknown_storage_class() {
|
||||
r#"
|
||||
@group(0) @binding(0) var<bad> texture: texture_2d<f32>;
|
||||
"#,
|
||||
r#"error: unknown address space: 'bad'
|
||||
r#"error: unknown address space: `bad`
|
||||
┌─ wgsl:2:39
|
||||
│
|
||||
2 │ @group(0) @binding(0) var<bad> texture: texture_2d<f32>;
|
||||
@@ -299,7 +299,7 @@ fn unknown_attribute() {
|
||||
@a
|
||||
fn x() {}
|
||||
"#,
|
||||
r#"error: unknown attribute: 'a'
|
||||
r#"error: unknown attribute: `a`
|
||||
┌─ wgsl:2:14
|
||||
│
|
||||
2 │ @a
|
||||
@@ -315,7 +315,7 @@ fn unknown_built_in() {
|
||||
r#"
|
||||
fn x(@builtin(unknown_built_in) y: u32) {}
|
||||
"#,
|
||||
r#"error: unknown builtin: 'unknown_built_in'
|
||||
r#"error: unknown builtin: `unknown_built_in`
|
||||
┌─ wgsl:2:27
|
||||
│
|
||||
2 │ fn x(@builtin(unknown_built_in) y: u32) {}
|
||||
@@ -331,7 +331,7 @@ fn unknown_access() {
|
||||
r#"
|
||||
var<storage,unknown_access> x: array<u32>;
|
||||
"#,
|
||||
r#"error: unknown access: 'unknown_access'
|
||||
r#"error: unknown access: `unknown_access`
|
||||
┌─ wgsl:2:25
|
||||
│
|
||||
2 │ var<storage,unknown_access> x: array<u32>;
|
||||
@@ -349,7 +349,7 @@ fn unknown_ident() {
|
||||
let a = b;
|
||||
}
|
||||
"#,
|
||||
r#"error: no definition in scope for identifier: 'b'
|
||||
r#"error: no definition in scope for identifier: `b`
|
||||
┌─ wgsl:3:25
|
||||
│
|
||||
3 │ let a = b;
|
||||
@@ -365,7 +365,7 @@ fn unknown_scalar_type() {
|
||||
r#"
|
||||
const a = vec2<vec2f>();
|
||||
"#,
|
||||
r#"error: unknown scalar type: 'vec2f'
|
||||
r#"error: unknown scalar type: `vec2f`
|
||||
┌─ wgsl:2:28
|
||||
│
|
||||
2 │ const a = vec2<vec2f>();
|
||||
@@ -383,7 +383,7 @@ fn unknown_type() {
|
||||
r#"
|
||||
const a: Vec = 10;
|
||||
"#,
|
||||
r#"error: unknown type: 'Vec'
|
||||
r#"error: unknown type: `Vec`
|
||||
┌─ wgsl:2:22
|
||||
│
|
||||
2 │ const a: Vec = 10;
|
||||
@@ -399,7 +399,7 @@ fn unknown_storage_format() {
|
||||
r#"
|
||||
const storage1: texture_storage_1d<rgba>;
|
||||
"#,
|
||||
r#"error: unknown storage format: 'rgba'
|
||||
r#"error: unknown storage format: `rgba`
|
||||
┌─ wgsl:2:48
|
||||
│
|
||||
2 │ const storage1: texture_storage_1d<rgba>;
|
||||
@@ -415,7 +415,7 @@ fn unknown_conservative_depth() {
|
||||
r#"
|
||||
@early_depth_test(abc) fn main() {}
|
||||
"#,
|
||||
r#"error: unknown conservative depth: 'abc'
|
||||
r#"error: unknown conservative depth: `abc`
|
||||
┌─ wgsl:2:31
|
||||
│
|
||||
2 │ @early_depth_test(abc) fn main() {}
|
||||
@@ -503,7 +503,7 @@ fn unknown_local_function() {
|
||||
for (a();;) {}
|
||||
}
|
||||
"#,
|
||||
r#"error: no definition in scope for identifier: 'a'
|
||||
r#"error: no definition in scope for identifier: `a`
|
||||
┌─ wgsl:3:22
|
||||
│
|
||||
3 │ for (a();;) {}
|
||||
@@ -1010,11 +1010,11 @@ fn invalid_arrays() {
|
||||
|
||||
check(
|
||||
"alias Bad = array<f32, true>;",
|
||||
r###"error: must be a const-expression that resolves to a concrete integer scalar (u32 or i32)
|
||||
r###"error: must be a const-expression that resolves to a concrete integer scalar (`u32` or `i32`)
|
||||
┌─ wgsl:1:24
|
||||
│
|
||||
1 │ alias Bad = array<f32, true>;
|
||||
│ ^^^^ must resolve to u32 or i32
|
||||
│ ^^^^ must resolve to `u32` or `i32`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -1024,11 +1024,11 @@ fn invalid_arrays() {
|
||||
const length: f32 = 2.718;
|
||||
alias Bad = array<f32, length>;
|
||||
"#,
|
||||
r###"error: must be a const-expression that resolves to a concrete integer scalar (u32 or i32)
|
||||
r###"error: must be a const-expression that resolves to a concrete integer scalar (`u32` or `i32`)
|
||||
┌─ wgsl:3:36
|
||||
│
|
||||
3 │ alias Bad = array<f32, length>;
|
||||
│ ^^^^^^ must resolve to u32 or i32
|
||||
│ ^^^^^^ must resolve to `u32` or `i32`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -1842,7 +1842,7 @@ fn assign_to_let() {
|
||||
4 │ a = 20;
|
||||
│ ^ cannot assign to this expression
|
||||
│
|
||||
= note: consider declaring 'a' with `var` instead of `let`
|
||||
= note: consider declaring `a` with `var` instead of `let`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -1862,7 +1862,7 @@ fn assign_to_let() {
|
||||
4 │ a[0] = 1;
|
||||
│ ^^^^ cannot assign to this expression
|
||||
│
|
||||
= note: consider declaring 'a' with `var` instead of `let`
|
||||
= note: consider declaring `a` with `var` instead of `let`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -1884,7 +1884,7 @@ fn assign_to_let() {
|
||||
6 │ a.a = 20;
|
||||
│ ^^^ cannot assign to this expression
|
||||
│
|
||||
= note: consider declaring 'a' with `var` instead of `let`
|
||||
= note: consider declaring `a` with `var` instead of `let`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -1954,7 +1954,7 @@ fn switch_signed_unsigned_mismatch() {
|
||||
4 │ case 1: {}
|
||||
│ ^ expected unsigned integer
|
||||
│
|
||||
= note: suffix the integer with a `u`: '1u'
|
||||
= note: suffix the integer with a `u`: `1u`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -1973,7 +1973,7 @@ fn switch_signed_unsigned_mismatch() {
|
||||
4 │ case 1u: {}
|
||||
│ ^^ expected signed integer
|
||||
│
|
||||
= note: remove the `u` suffix: '1'
|
||||
= note: remove the `u` suffix: `1`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -2407,11 +2407,11 @@ fn const_assert_must_be_bool() {
|
||||
"
|
||||
const_assert(5); // 5 is not bool
|
||||
",
|
||||
r###"error: must be a const-expression that resolves to a bool
|
||||
r###"error: must be a const-expression that resolves to a `bool`
|
||||
┌─ wgsl:2:26
|
||||
│
|
||||
2 │ const_assert(5); // 5 is not bool
|
||||
│ ^ must resolve to bool
|
||||
│ ^ must resolve to `bool`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -2423,11 +2423,11 @@ fn const_assert_failed() {
|
||||
"
|
||||
const_assert(false);
|
||||
",
|
||||
r###"error: const_assert failure
|
||||
r###"error: `const_assert` failure
|
||||
┌─ wgsl:2:26
|
||||
│
|
||||
2 │ const_assert(false);
|
||||
│ ^^^^^ evaluates to false
|
||||
│ ^^^^^ evaluates to `false`
|
||||
|
||||
"###,
|
||||
);
|
||||
@@ -2437,11 +2437,11 @@ fn const_assert_failed() {
|
||||
fn reject_utf8_bom() {
|
||||
check(
|
||||
"\u{FEFF}fn main() {}",
|
||||
r#"error: expected global item ('struct', 'const', 'var', 'alias', 'fn', 'diagnostic', 'enable', 'requires', ';') or the end of the file, found "\u{feff}"
|
||||
r#"error: expected global item (`struct`, `const`, `var`, `alias`, `fn`, `diagnostic`, `enable`, `requires`, `;`) or the end of the file, found "\u{feff}"
|
||||
┌─ wgsl:1:1
|
||||
│
|
||||
1 │ fn main() {}
|
||||
│ expected global item ('struct', 'const', 'var', 'alias', 'fn', 'diagnostic', 'enable', 'requires', ';') or the end of the file
|
||||
│ expected global item (`struct`, `const`, `var`, `alias`, `fn`, `diagnostic`, `enable`, `requires`, `;`) or the end of the file
|
||||
|
||||
"#,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user