Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix several ICEs related to malformed #[repr(...)] attributes #87013

Merged
merged 1 commit into from
Jul 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 96 additions & 8 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Comment on lines +874 to +886
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you have no conditional changes on the diagnostic, you can rely on chaining instead:

Suggested change
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();
struct_span_err!(
diagnostic,
item.span(),
E0589,
"invalid `repr(align)` attribute: `align` needs an argument"
).span_suggestion(
item.span(),
"supply an argument here",
"align(...)".to_string(),
Applicability::HasPlaceholders,
).emit();

(Might need to run ./x.py fmt to fix the formatting here)

recognised = true;
None
}
name => int_type_of_word(name).map(ReprInt),
};

Expand All @@ -891,53 +908,124 @@ 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 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,
);
}
ast::LitKind::Str(s, _) => {
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");
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/attributes/nonterminal-expansion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}
Expand Down
14 changes: 13 additions & 1 deletion src/test/ui/attributes/nonterminal-expansion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 34 additions & 0 deletions src/test/ui/repr/issue-83921-ice.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 46 additions & 0 deletions src/test/ui/repr/issue-83921-ice.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 9 additions & 0 deletions src/test/ui/repr/issue-83921-pretty.normal.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 19 additions & 0 deletions src/test/ui/repr/issue-83921-pretty.pretty.stdout
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions src/test/ui/repr/issue-83921-pretty.rs
Original file line number Diff line number Diff line change
@@ -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() {}