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::simd => Some(ReprSimd),
|
||||||
sym::transparent => Some(ReprTransparent),
|
sym::transparent => Some(ReprTransparent),
|
||||||
sym::no_niche => Some(ReprNoNiche),
|
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),
|
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)),
|
Ok(literal) => acc.push(ReprPacked(literal)),
|
||||||
Err(message) => literal_error = Some(message),
|
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 {
|
if let Some(literal_error) = literal_error {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
diagnostic,
|
diagnostic,
|
||||||
item.span(),
|
item.span(),
|
||||||
E0589,
|
E0589,
|
||||||
"invalid `repr(align)` attribute: {}",
|
"invalid `repr({})` attribute: {}",
|
||||||
|
name.to_ident_string(),
|
||||||
literal_error
|
literal_error
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
} else if let Some(meta_item) = item.meta_item() {
|
} 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 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;
|
recognised = true;
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
diagnostic,
|
diagnostic,
|
||||||
item.span(),
|
item.span(),
|
||||||
E0693,
|
E0693,
|
||||||
"incorrect `repr(align)` attribute format"
|
"incorrect `repr({})` attribute format",
|
||||||
|
name,
|
||||||
);
|
);
|
||||||
match value.kind {
|
match value.kind {
|
||||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
item.span(),
|
item.span(),
|
||||||
"use parentheses instead",
|
"use parentheses instead",
|
||||||
format!("align({})", int),
|
format!("{}({})", name, int),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -925,23 +956,80 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
|||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
item.span(),
|
item.span(),
|
||||||
"use parentheses instead",
|
"use parentheses instead",
|
||||||
format!("align({})", s),
|
format!("{}({})", name, s),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
err.emit();
|
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 {
|
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");
|
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
macro_rules! pass_nonterminal {
|
macro_rules! pass_nonterminal {
|
||||||
($n:expr) => {
|
($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;
|
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)
|
= 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