Enhance well-formedness checks for #[repr(...)]
attributes
This commit is contained in:
parent
e916b7cb77
commit
a7bfd35966
@ -870,6 +870,23 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
sym::simd => Some(ReprSimd),
|
||||
sym::transparent => Some(ReprTransparent),
|
||||
sym::no_niche => Some(ReprNoNiche),
|
||||
sym::align => {
|
||||
let mut err = struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0589,
|
||||
"invalid `repr(align)` attribute: `align` needs an argument"
|
||||
);
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"supply an argument here",
|
||||
"align(...)".to_string(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
err.emit();
|
||||
recognised = true;
|
||||
None
|
||||
}
|
||||
name => int_type_of_word(name).map(ReprInt),
|
||||
};
|
||||
|
||||
@ -891,33 +908,47 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
Ok(literal) => acc.push(ReprPacked(literal)),
|
||||
Err(message) => literal_error = Some(message),
|
||||
};
|
||||
} else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
|
||||
|| int_type_of_word(name).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0552,
|
||||
"invalid representation hint: `{}` does not take a parenthesized argument list",
|
||||
name.to_ident_string(),
|
||||
).emit();
|
||||
}
|
||||
if let Some(literal_error) = literal_error {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0589,
|
||||
"invalid `repr(align)` attribute: {}",
|
||||
"invalid `repr({})` attribute: {}",
|
||||
name.to_ident_string(),
|
||||
literal_error
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else if let Some(meta_item) = item.meta_item() {
|
||||
if meta_item.has_name(sym::align) {
|
||||
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
|
||||
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
|
||||
let name = meta_item.name_or_empty().to_ident_string();
|
||||
recognised = true;
|
||||
let mut err = struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0693,
|
||||
"incorrect `repr(align)` attribute format"
|
||||
"incorrect `repr({})` attribute format",
|
||||
name,
|
||||
);
|
||||
match value.kind {
|
||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("align({})", int),
|
||||
format!("{}({})", name, int),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
@ -925,23 +956,80 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("align({})", s),
|
||||
format!("{}({})", name, s),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.emit();
|
||||
} else {
|
||||
if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent | sym::no_niche
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0552,
|
||||
"invalid representation hint: `{}` does not take a value",
|
||||
meta_item.name_or_empty().to_ident_string(),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
} else if let MetaItemKind::List(_) = meta_item.kind {
|
||||
if meta_item.has_name(sym::align) {
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0693,
|
||||
"incorrect `repr(align)` attribute format: \
|
||||
`align` takes exactly one argument in parentheses"
|
||||
)
|
||||
.emit();
|
||||
} else if meta_item.has_name(sym::packed) {
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0552,
|
||||
"incorrect `repr(packed)` attribute format: \
|
||||
`packed` takes exactly one parenthesized argument, \
|
||||
or no parentheses at all"
|
||||
)
|
||||
.emit();
|
||||
} else if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent | sym::no_niche
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0552,
|
||||
"invalid representation hint: `{}` does not take a parenthesized argument list",
|
||||
meta_item.name_or_empty().to_ident_string(),
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
if !recognised {
|
||||
// Not a word we recognize
|
||||
// Not a word we recognize. This will be caught and reported by
|
||||
// the `check_mod_attrs` pass, but this pass doesn't always run
|
||||
// (e.g. if we only pretty-print the source), so we have to gate
|
||||
// the `delay_span_bug` call as follows:
|
||||
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
|
||||
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
macro_rules! pass_nonterminal {
|
||||
($n:expr) => {
|
||||
#[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
|
||||
#[repr(align($n))]
|
||||
//~^ ERROR expected unsuffixed literal or identifier, found `n!()`
|
||||
//~| ERROR incorrect `repr(align)` attribute format
|
||||
struct S;
|
||||
};
|
||||
}
|
||||
|
@ -9,5 +9,17 @@ LL | pass_nonterminal!(n!());
|
||||
|
|
||||
= note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
--> $DIR/nonterminal-expansion.rs:5:16
|
||||
|
|
||||
LL | #[repr(align($n))]
|
||||
| ^^^^^^^^^
|
||||
...
|
||||
LL | pass_nonterminal!(n!());
|
||||
| ------------------------ in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0693`.
|
||||
|
34
src/test/ui/repr/issue-83921-ice.rs
Normal file
34
src/test/ui/repr/issue-83921-ice.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Regression test for various ICEs inspired by
|
||||
// https://github.com/rust-lang/rust/issues/83921#issuecomment-814640734
|
||||
|
||||
// compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
|
||||
#[repr(packed())]
|
||||
//~^ ERROR: incorrect `repr(packed)` attribute format
|
||||
struct S1;
|
||||
|
||||
#[repr(align)]
|
||||
//~^ ERROR: invalid `repr(align)` attribute
|
||||
struct S2;
|
||||
|
||||
#[repr(align(2, 4))]
|
||||
//~^ ERROR: incorrect `repr(align)` attribute format
|
||||
struct S3;
|
||||
|
||||
#[repr(align())]
|
||||
//~^ ERROR: incorrect `repr(align)` attribute format
|
||||
struct S4;
|
||||
|
||||
#[repr(i8())]
|
||||
//~^ ERROR: invalid representation hint
|
||||
enum E1 { A, B }
|
||||
|
||||
#[repr(u32(42))]
|
||||
//~^ ERROR: invalid representation hint
|
||||
enum E2 { A, B }
|
||||
|
||||
#[repr(i64 = 2)]
|
||||
//~^ ERROR: invalid representation hint
|
||||
enum E3 { A, B }
|
||||
|
||||
fn main() {}
|
46
src/test/ui/repr/issue-83921-ice.stderr
Normal file
46
src/test/ui/repr/issue-83921-ice.stderr
Normal file
@ -0,0 +1,46 @@
|
||||
error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
|
||||
--> $DIR/issue-83921-ice.rs:6:8
|
||||
|
|
||||
LL | #[repr(packed())]
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
|
||||
--> $DIR/issue-83921-ice.rs:10:8
|
||||
|
|
||||
LL | #[repr(align)]
|
||||
| ^^^^^ help: supply an argument here: `align(...)`
|
||||
|
||||
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
--> $DIR/issue-83921-ice.rs:14:8
|
||||
|
|
||||
LL | #[repr(align(2, 4))]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
--> $DIR/issue-83921-ice.rs:18:8
|
||||
|
|
||||
LL | #[repr(align())]
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `i8` does not take a parenthesized argument list
|
||||
--> $DIR/issue-83921-ice.rs:22:8
|
||||
|
|
||||
LL | #[repr(i8())]
|
||||
| ^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `u32` does not take a parenthesized argument list
|
||||
--> $DIR/issue-83921-ice.rs:26:8
|
||||
|
|
||||
LL | #[repr(u32(42))]
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `i64` does not take a value
|
||||
--> $DIR/issue-83921-ice.rs:30:8
|
||||
|
|
||||
LL | #[repr(i64 = 2)]
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0552, E0589, E0693.
|
||||
For more information about an error, try `rustc --explain E0552`.
|
9
src/test/ui/repr/issue-83921-pretty.normal.stderr
Normal file
9
src/test/ui/repr/issue-83921-pretty.normal.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0565]: meta item in `repr` must be an identifier
|
||||
--> $DIR/issue-83921-pretty.rs:10:8
|
||||
|
|
||||
LL | #[repr("C")]
|
||||
| ^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0565`.
|
19
src/test/ui/repr/issue-83921-pretty.pretty.stdout
Normal file
19
src/test/ui/repr/issue-83921-pretty.pretty.stdout
Normal file
@ -0,0 +1,19 @@
|
||||
#![feature(prelude_import)]
|
||||
#![no_std]
|
||||
#[prelude_import]
|
||||
use ::std::prelude::rust_2015::*;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
// Regression test for #83921. A `delay_span_bug()` call was issued, but the
|
||||
// error was never reported because the pass responsible for detecting and
|
||||
// reporting the error does not run in certain modes of pretty-printing.
|
||||
|
||||
// Make sure the error is reported if we do not just pretty-print:
|
||||
// revisions: pretty normal
|
||||
// [pretty]compile-flags: -Zunpretty=everybody_loops
|
||||
// [pretty]check-pass
|
||||
#[repr("C")]
|
||||
struct A {
|
||||
}
|
||||
|
||||
fn main() { loop { } }
|
14
src/test/ui/repr/issue-83921-pretty.rs
Normal file
14
src/test/ui/repr/issue-83921-pretty.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Regression test for #83921. A `delay_span_bug()` call was issued, but the
|
||||
// error was never reported because the pass responsible for detecting and
|
||||
// reporting the error does not run in certain modes of pretty-printing.
|
||||
|
||||
// Make sure the error is reported if we do not just pretty-print:
|
||||
// revisions: pretty normal
|
||||
// [pretty]compile-flags: -Zunpretty=everybody_loops
|
||||
// [pretty]check-pass
|
||||
|
||||
#[repr("C")]
|
||||
//[normal]~^ ERROR: meta item in `repr` must be an identifier [E0565]
|
||||
struct A {}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user