Skip to content

Commit 849e563

Browse files
authored
Rollup merge of #77343 - varkor:rustc_args_required_const-validation, r=lcnr
Validate `rustc_args_required_const` Fixes #74608.
2 parents 73258f8 + 609786d commit 849e563

File tree

4 files changed

+176
-10
lines changed

4 files changed

+176
-10
lines changed

Diff for: compiler/rustc_mir/src/transform/promote_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
137137
LitKind::Int(a, _) => {
138138
ret.push(a as usize);
139139
}
140-
_ => return None,
140+
_ => bug!("invalid arg index"),
141141
}
142142
}
143143
Some(ret)

Diff for: compiler/rustc_passes/src/check_attr.rs

+101-9
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use rustc_middle::hir::map::Map;
88
use rustc_middle::ty::query::Providers;
99
use rustc_middle::ty::TyCtxt;
1010

11-
use rustc_ast::{Attribute, NestedMetaItem};
12-
use rustc_errors::struct_span_err;
11+
use rustc_ast::{Attribute, LitKind, NestedMetaItem};
12+
use rustc_errors::{pluralize, struct_span_err};
1313
use rustc_hir as hir;
1414
use rustc_hir::def_id::LocalDefId;
1515
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
16-
use rustc_hir::{self, HirId, Item, ItemKind, TraitItem};
16+
use rustc_hir::{self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem};
1717
use rustc_hir::{MethodKind, Target};
1818
use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES};
1919
use rustc_session::parse::feature_err;
@@ -43,6 +43,12 @@ pub(crate) fn target_from_impl_item<'tcx>(
4343
}
4444
}
4545

46+
#[derive(Clone, Copy)]
47+
enum ItemLike<'tcx> {
48+
Item(&'tcx Item<'tcx>),
49+
ForeignItem(&'tcx ForeignItem<'tcx>),
50+
}
51+
4652
struct CheckAttrVisitor<'tcx> {
4753
tcx: TyCtxt<'tcx>,
4854
}
@@ -55,7 +61,7 @@ impl CheckAttrVisitor<'tcx> {
5561
attrs: &'hir [Attribute],
5662
span: &Span,
5763
target: Target,
58-
item: Option<&Item<'_>>,
64+
item: Option<ItemLike<'_>>,
5965
) {
6066
let mut is_valid = true;
6167
for attr in attrs {
@@ -75,6 +81,8 @@ impl CheckAttrVisitor<'tcx> {
7581
self.check_no_link(&attr, span, target)
7682
} else if self.tcx.sess.check_name(attr, sym::export_name) {
7783
self.check_export_name(&attr, span, target)
84+
} else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
85+
self.check_rustc_args_required_const(&attr, span, target, item)
7886
} else {
7987
// lint-only checks
8088
if self.tcx.sess.check_name(attr, sym::cold) {
@@ -400,6 +408,71 @@ impl CheckAttrVisitor<'tcx> {
400408
}
401409
}
402410

411+
/// Checks if `#[rustc_args_required_const]` is applied to a function and has a valid argument.
412+
fn check_rustc_args_required_const(
413+
&self,
414+
attr: &Attribute,
415+
span: &Span,
416+
target: Target,
417+
item: Option<ItemLike<'_>>,
418+
) -> bool {
419+
if let Target::Fn | Target::Method(..) | Target::ForeignFn = target {
420+
let mut invalid_args = vec![];
421+
for meta in attr.meta_item_list().expect("no meta item list") {
422+
if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
423+
if let Some(ItemLike::Item(Item {
424+
kind: ItemKind::Fn(FnSig { decl, .. }, ..),
425+
..
426+
}))
427+
| Some(ItemLike::ForeignItem(ForeignItem {
428+
kind: ForeignItemKind::Fn(decl, ..),
429+
..
430+
})) = item
431+
{
432+
let arg_count = decl.inputs.len() as u128;
433+
if *val >= arg_count {
434+
let span = meta.span();
435+
self.tcx
436+
.sess
437+
.struct_span_err(span, "index exceeds number of arguments")
438+
.span_label(
439+
span,
440+
format!(
441+
"there {} only {} argument{}",
442+
if arg_count != 1 { "are" } else { "is" },
443+
arg_count,
444+
pluralize!(arg_count)
445+
),
446+
)
447+
.emit();
448+
return false;
449+
}
450+
} else {
451+
bug!("should be a function item");
452+
}
453+
} else {
454+
invalid_args.push(meta.span());
455+
}
456+
}
457+
if !invalid_args.is_empty() {
458+
self.tcx
459+
.sess
460+
.struct_span_err(invalid_args, "arguments should be non-negative integers")
461+
.emit();
462+
false
463+
} else {
464+
true
465+
}
466+
} else {
467+
self.tcx
468+
.sess
469+
.struct_span_err(attr.span, "attribute should be applied to a function")
470+
.span_label(*span, "not a function")
471+
.emit();
472+
false
473+
}
474+
}
475+
403476
/// Checks if `#[link_section]` is applied to a function or static.
404477
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
405478
match target {
@@ -448,7 +521,7 @@ impl CheckAttrVisitor<'tcx> {
448521
attrs: &'hir [Attribute],
449522
span: &Span,
450523
target: Target,
451-
item: Option<&Item<'_>>,
524+
item: Option<ItemLike<'_>>,
452525
hir_id: HirId,
453526
) {
454527
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
@@ -564,7 +637,14 @@ impl CheckAttrVisitor<'tcx> {
564637
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
565638
if (int_reprs > 1)
566639
|| (is_simd && is_c)
567-
|| (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item)))
640+
|| (int_reprs == 1
641+
&& is_c
642+
&& item.map_or(false, |item| {
643+
if let ItemLike::Item(item) = item {
644+
return is_c_like_enum(item);
645+
}
646+
return false;
647+
}))
568648
{
569649
self.tcx.struct_span_lint_hir(
570650
CONFLICTING_REPR_HINTS,
@@ -649,7 +729,13 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
649729

650730
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
651731
let target = Target::from_item(item);
652-
self.check_attributes(item.hir_id, item.attrs, &item.span, target, Some(item));
732+
self.check_attributes(
733+
item.hir_id,
734+
item.attrs,
735+
&item.span,
736+
target,
737+
Some(ItemLike::Item(item)),
738+
);
653739
intravisit::walk_item(self, item)
654740
}
655741

@@ -659,9 +745,15 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
659745
intravisit::walk_trait_item(self, trait_item)
660746
}
661747

662-
fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem<'tcx>) {
748+
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
663749
let target = Target::from_foreign_item(f_item);
664-
self.check_attributes(f_item.hir_id, &f_item.attrs, &f_item.span, target, None);
750+
self.check_attributes(
751+
f_item.hir_id,
752+
&f_item.attrs,
753+
&f_item.span,
754+
target,
755+
Some(ItemLike::ForeignItem(f_item)),
756+
);
665757
intravisit::walk_foreign_item(self, f_item)
666758
}
667759

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_args_required_const(0)] //~ ERROR index exceeds number of arguments
4+
fn foo1() {}
5+
6+
#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments
7+
fn foo2(_: u8) {}
8+
9+
#[rustc_args_required_const(a)] //~ ERROR arguments should be non-negative integers
10+
fn foo4() {}
11+
12+
#[rustc_args_required_const(1, a, 2, b)] //~ ERROR arguments should be non-negative integers
13+
fn foo5(_: u8, _: u8, _: u8) {}
14+
15+
#[rustc_args_required_const(0)] //~ ERROR attribute should be applied to a function
16+
struct S;
17+
18+
#[rustc_args_required_const(0usize)] //~ ERROR suffixed literals are not allowed in attributes
19+
fn foo6(_: u8) {}
20+
21+
extern {
22+
#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments
23+
fn foo7(_: u8);
24+
}
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error: suffixed literals are not allowed in attributes
2+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:18:29
3+
|
4+
LL | #[rustc_args_required_const(0usize)]
5+
| ^^^^^^
6+
|
7+
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
8+
9+
error: index exceeds number of arguments
10+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29
11+
|
12+
LL | #[rustc_args_required_const(0)]
13+
| ^ there are only 0 arguments
14+
15+
error: index exceeds number of arguments
16+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:6:29
17+
|
18+
LL | #[rustc_args_required_const(1)]
19+
| ^ there is only 1 argument
20+
21+
error: arguments should be non-negative integers
22+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:9:29
23+
|
24+
LL | #[rustc_args_required_const(a)]
25+
| ^
26+
27+
error: arguments should be non-negative integers
28+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:12:32
29+
|
30+
LL | #[rustc_args_required_const(1, a, 2, b)]
31+
| ^ ^
32+
33+
error: attribute should be applied to a function
34+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:15:1
35+
|
36+
LL | #[rustc_args_required_const(0)]
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
LL | struct S;
39+
| --------- not a function
40+
41+
error: index exceeds number of arguments
42+
--> $DIR/invalid-rustc_args_required_const-arguments.rs:22:33
43+
|
44+
LL | #[rustc_args_required_const(1)]
45+
| ^ there is only 1 argument
46+
47+
error: aborting due to 7 previous errors
48+

0 commit comments

Comments
 (0)