diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 20971ebb95748..b7b053cd5ddb7 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -870,6 +870,23 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec { 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 { 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 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,19 +956,76 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec { 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 - diagnostic.delay_span_bug(item.span(), "unrecognized representation hint"); + // 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"); + } } } } diff --git a/src/test/ui/attributes/nonterminal-expansion.rs b/src/test/ui/attributes/nonterminal-expansion.rs index d663431d6836f..97bf225f0cc73 100644 --- a/src/test/ui/attributes/nonterminal-expansion.rs +++ b/src/test/ui/attributes/nonterminal-expansion.rs @@ -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; }; } diff --git a/src/test/ui/attributes/nonterminal-expansion.stderr b/src/test/ui/attributes/nonterminal-expansion.stderr index 4124f8cea8ebf..9bf36f3c58e81 100644 --- a/src/test/ui/attributes/nonterminal-expansion.stderr +++ b/src/test/ui/attributes/nonterminal-expansion.stderr @@ -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`. diff --git a/src/test/ui/repr/issue-83921-ice.rs b/src/test/ui/repr/issue-83921-ice.rs new file mode 100644 index 0000000000000..70583eb9bd332 --- /dev/null +++ b/src/test/ui/repr/issue-83921-ice.rs @@ -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() {} diff --git a/src/test/ui/repr/issue-83921-ice.stderr b/src/test/ui/repr/issue-83921-ice.stderr new file mode 100644 index 0000000000000..32c450410eace --- /dev/null +++ b/src/test/ui/repr/issue-83921-ice.stderr @@ -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`. diff --git a/src/test/ui/repr/issue-83921-pretty.normal.stderr b/src/test/ui/repr/issue-83921-pretty.normal.stderr new file mode 100644 index 0000000000000..6b7e831ed2f7a --- /dev/null +++ b/src/test/ui/repr/issue-83921-pretty.normal.stderr @@ -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`. diff --git a/src/test/ui/repr/issue-83921-pretty.pretty.stdout b/src/test/ui/repr/issue-83921-pretty.pretty.stdout new file mode 100644 index 0000000000000..dad3641f0f5af --- /dev/null +++ b/src/test/ui/repr/issue-83921-pretty.pretty.stdout @@ -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 { } } diff --git a/src/test/ui/repr/issue-83921-pretty.rs b/src/test/ui/repr/issue-83921-pretty.rs new file mode 100644 index 0000000000000..d5d36470f11ac --- /dev/null +++ b/src/test/ui/repr/issue-83921-pretty.rs @@ -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() {}