Skip to content

Commit 945458d

Browse files
authored
Rollup merge of #87013 - FabianWolff:issue-83921, r=estebank
Fix several ICEs related to malformed `#[repr(...)]` attributes This PR fixes #83921. #83921 actually contains two related but distinct issues (one of them incorrectly reported as a duplicate in #83921 (comment)): In the first, a call to `delay_span_bug` leads to an ICE when compiling with `-Zunpretty=everybody_loops` (and some other pretty-printing modes), because the corresponding error is emitted in a later pass, which does not run when only pretty-printing is requested. The second issue is about parsing `#[repr(...)]` attributes. Currently, all of the following cause an ICE when applied to a struct/enum: ```rust #[repr(packed())] #[repr(align)] #[repr(align(2, 4))] #[repr(align())] #[repr(i8())] #[repr(u32(42))] #[repr(i64 = 2)] ``` I have fixed this by expanding the well-formedness checks in `find_repr_attrs()`.
2 parents 0ca5fc2 + a7bfd35 commit 945458d

8 files changed

+234
-10
lines changed

compiler/rustc_attr/src/builtin.rs

+96-8
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,23 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
870870
sym::simd => Some(ReprSimd),
871871
sym::transparent => Some(ReprTransparent),
872872
sym::no_niche => Some(ReprNoNiche),
873+
sym::align => {
874+
let mut err = struct_span_err!(
875+
diagnostic,
876+
item.span(),
877+
E0589,
878+
"invalid `repr(align)` attribute: `align` needs an argument"
879+
);
880+
err.span_suggestion(
881+
item.span(),
882+
"supply an argument here",
883+
"align(...)".to_string(),
884+
Applicability::HasPlaceholders,
885+
);
886+
err.emit();
887+
recognised = true;
888+
None
889+
}
873890
name => int_type_of_word(name).map(ReprInt),
874891
};
875892

@@ -891,53 +908,124 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
891908
Ok(literal) => acc.push(ReprPacked(literal)),
892909
Err(message) => literal_error = Some(message),
893910
};
911+
} else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
912+
|| int_type_of_word(name).is_some()
913+
{
914+
recognised = true;
915+
struct_span_err!(
916+
diagnostic,
917+
item.span(),
918+
E0552,
919+
"invalid representation hint: `{}` does not take a parenthesized argument list",
920+
name.to_ident_string(),
921+
).emit();
894922
}
895923
if let Some(literal_error) = literal_error {
896924
struct_span_err!(
897925
diagnostic,
898926
item.span(),
899927
E0589,
900-
"invalid `repr(align)` attribute: {}",
928+
"invalid `repr({})` attribute: {}",
929+
name.to_ident_string(),
901930
literal_error
902931
)
903932
.emit();
904933
}
905934
} else if let Some(meta_item) = item.meta_item() {
906-
if meta_item.has_name(sym::align) {
907-
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
935+
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
936+
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
937+
let name = meta_item.name_or_empty().to_ident_string();
908938
recognised = true;
909939
let mut err = struct_span_err!(
910940
diagnostic,
911941
item.span(),
912942
E0693,
913-
"incorrect `repr(align)` attribute format"
943+
"incorrect `repr({})` attribute format",
944+
name,
914945
);
915946
match value.kind {
916947
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
917948
err.span_suggestion(
918949
item.span(),
919950
"use parentheses instead",
920-
format!("align({})", int),
951+
format!("{}({})", name, int),
921952
Applicability::MachineApplicable,
922953
);
923954
}
924955
ast::LitKind::Str(s, _) => {
925956
err.span_suggestion(
926957
item.span(),
927958
"use parentheses instead",
928-
format!("align({})", s),
959+
format!("{}({})", name, s),
929960
Applicability::MachineApplicable,
930961
);
931962
}
932963
_ => {}
933964
}
934965
err.emit();
966+
} else {
967+
if matches!(
968+
meta_item.name_or_empty(),
969+
sym::C | sym::simd | sym::transparent | sym::no_niche
970+
) || int_type_of_word(meta_item.name_or_empty()).is_some()
971+
{
972+
recognised = true;
973+
struct_span_err!(
974+
diagnostic,
975+
meta_item.span,
976+
E0552,
977+
"invalid representation hint: `{}` does not take a value",
978+
meta_item.name_or_empty().to_ident_string(),
979+
)
980+
.emit();
981+
}
982+
}
983+
} else if let MetaItemKind::List(_) = meta_item.kind {
984+
if meta_item.has_name(sym::align) {
985+
recognised = true;
986+
struct_span_err!(
987+
diagnostic,
988+
meta_item.span,
989+
E0693,
990+
"incorrect `repr(align)` attribute format: \
991+
`align` takes exactly one argument in parentheses"
992+
)
993+
.emit();
994+
} else if meta_item.has_name(sym::packed) {
995+
recognised = true;
996+
struct_span_err!(
997+
diagnostic,
998+
meta_item.span,
999+
E0552,
1000+
"incorrect `repr(packed)` attribute format: \
1001+
`packed` takes exactly one parenthesized argument, \
1002+
or no parentheses at all"
1003+
)
1004+
.emit();
1005+
} else if matches!(
1006+
meta_item.name_or_empty(),
1007+
sym::C | sym::simd | sym::transparent | sym::no_niche
1008+
) || int_type_of_word(meta_item.name_or_empty()).is_some()
1009+
{
1010+
recognised = true;
1011+
struct_span_err!(
1012+
diagnostic,
1013+
meta_item.span,
1014+
E0552,
1015+
"invalid representation hint: `{}` does not take a parenthesized argument list",
1016+
meta_item.name_or_empty().to_ident_string(),
1017+
).emit();
9351018
}
9361019
}
9371020
}
9381021
if !recognised {
939-
// Not a word we recognize
940-
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
1022+
// Not a word we recognize. This will be caught and reported by
1023+
// the `check_mod_attrs` pass, but this pass doesn't always run
1024+
// (e.g. if we only pretty-print the source), so we have to gate
1025+
// the `delay_span_bug` call as follows:
1026+
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
1027+
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
1028+
}
9411029
}
9421030
}
9431031
}

src/test/ui/attributes/nonterminal-expansion.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
macro_rules! pass_nonterminal {
44
($n:expr) => {
5-
#[repr(align($n))] //~ ERROR expected unsuffixed literal or identifier, found `n!()`
5+
#[repr(align($n))]
6+
//~^ ERROR expected unsuffixed literal or identifier, found `n!()`
7+
//~| ERROR incorrect `repr(align)` attribute format
68
struct S;
79
};
810
}

src/test/ui/attributes/nonterminal-expansion.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,17 @@ LL | pass_nonterminal!(n!());
99
|
1010
= note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
1111

12-
error: aborting due to previous error
12+
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
13+
--> $DIR/nonterminal-expansion.rs:5:16
14+
|
15+
LL | #[repr(align($n))]
16+
| ^^^^^^^^^
17+
...
18+
LL | pass_nonterminal!(n!());
19+
| ------------------------ in this macro invocation
20+
|
21+
= note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
22+
23+
error: aborting due to 2 previous errors
1324

25+
For more information about this error, try `rustc --explain E0693`.

src/test/ui/repr/issue-83921-ice.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Regression test for various ICEs inspired by
2+
// https://github.com/rust-lang/rust/issues/83921#issuecomment-814640734
3+
4+
// compile-flags: -Zdeduplicate-diagnostics=yes
5+
6+
#[repr(packed())]
7+
//~^ ERROR: incorrect `repr(packed)` attribute format
8+
struct S1;
9+
10+
#[repr(align)]
11+
//~^ ERROR: invalid `repr(align)` attribute
12+
struct S2;
13+
14+
#[repr(align(2, 4))]
15+
//~^ ERROR: incorrect `repr(align)` attribute format
16+
struct S3;
17+
18+
#[repr(align())]
19+
//~^ ERROR: incorrect `repr(align)` attribute format
20+
struct S4;
21+
22+
#[repr(i8())]
23+
//~^ ERROR: invalid representation hint
24+
enum E1 { A, B }
25+
26+
#[repr(u32(42))]
27+
//~^ ERROR: invalid representation hint
28+
enum E2 { A, B }
29+
30+
#[repr(i64 = 2)]
31+
//~^ ERROR: invalid representation hint
32+
enum E3 { A, B }
33+
34+
fn main() {}
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
2+
--> $DIR/issue-83921-ice.rs:6:8
3+
|
4+
LL | #[repr(packed())]
5+
| ^^^^^^^^
6+
7+
error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
8+
--> $DIR/issue-83921-ice.rs:10:8
9+
|
10+
LL | #[repr(align)]
11+
| ^^^^^ help: supply an argument here: `align(...)`
12+
13+
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
14+
--> $DIR/issue-83921-ice.rs:14:8
15+
|
16+
LL | #[repr(align(2, 4))]
17+
| ^^^^^^^^^^^
18+
19+
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
20+
--> $DIR/issue-83921-ice.rs:18:8
21+
|
22+
LL | #[repr(align())]
23+
| ^^^^^^^
24+
25+
error[E0552]: invalid representation hint: `i8` does not take a parenthesized argument list
26+
--> $DIR/issue-83921-ice.rs:22:8
27+
|
28+
LL | #[repr(i8())]
29+
| ^^^^
30+
31+
error[E0552]: invalid representation hint: `u32` does not take a parenthesized argument list
32+
--> $DIR/issue-83921-ice.rs:26:8
33+
|
34+
LL | #[repr(u32(42))]
35+
| ^^^^^^^
36+
37+
error[E0552]: invalid representation hint: `i64` does not take a value
38+
--> $DIR/issue-83921-ice.rs:30:8
39+
|
40+
LL | #[repr(i64 = 2)]
41+
| ^^^^^^^
42+
43+
error: aborting due to 7 previous errors
44+
45+
Some errors have detailed explanations: E0552, E0589, E0693.
46+
For more information about an error, try `rustc --explain E0552`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0565]: meta item in `repr` must be an identifier
2+
--> $DIR/issue-83921-pretty.rs:10:8
3+
|
4+
LL | #[repr("C")]
5+
| ^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0565`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(prelude_import)]
2+
#![no_std]
3+
#[prelude_import]
4+
use ::std::prelude::rust_2015::*;
5+
#[macro_use]
6+
extern crate std;
7+
// Regression test for #83921. A `delay_span_bug()` call was issued, but the
8+
// error was never reported because the pass responsible for detecting and
9+
// reporting the error does not run in certain modes of pretty-printing.
10+
11+
// Make sure the error is reported if we do not just pretty-print:
12+
// revisions: pretty normal
13+
// [pretty]compile-flags: -Zunpretty=everybody_loops
14+
// [pretty]check-pass
15+
#[repr("C")]
16+
struct A {
17+
}
18+
19+
fn main() { loop { } }
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Regression test for #83921. A `delay_span_bug()` call was issued, but the
2+
// error was never reported because the pass responsible for detecting and
3+
// reporting the error does not run in certain modes of pretty-printing.
4+
5+
// Make sure the error is reported if we do not just pretty-print:
6+
// revisions: pretty normal
7+
// [pretty]compile-flags: -Zunpretty=everybody_loops
8+
// [pretty]check-pass
9+
10+
#[repr("C")]
11+
//[normal]~^ ERROR: meta item in `repr` must be an identifier [E0565]
12+
struct A {}
13+
14+
fn main() {}

0 commit comments

Comments
 (0)