Skip to content

Commit 8bb2946

Browse files
committed
feature error span on attr. for fn_must_use, SIMD/align, macro reëxport
There were several feature-gated attributes for which the feature-not-available error spans would point to the item annotated with the gated attribute, when it would make more sense for the span to point to the attribute itself: if the attribute is removed, the function/struct/&c. likely still makes sense and the program will compile. (Note that we decline to make the analogous change for the `main`, `start`, and `plugin_registrar` features, for in those cases it makes sense for the span to implicate the entire function, of which there is little hope of using without the gated attribute.)
1 parent e266888 commit 8bb2946

10 files changed

+107
-36
lines changed

src/libsyntax/attr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ pub fn contains_name(attrs: &[Attribute], name: &str) -> bool {
490490
})
491491
}
492492

493+
pub fn find_by_name<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> {
494+
attrs.iter().find(|attr| attr.check_name(name))
495+
}
496+
493497
pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<Symbol> {
494498
attrs.iter()
495499
.find(|at| at.check_name(name))

src/libsyntax/feature_gate.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -1248,8 +1248,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
12481248
fn visit_item(&mut self, i: &'a ast::Item) {
12491249
match i.node {
12501250
ast::ItemKind::ExternCrate(_) => {
1251-
if attr::contains_name(&i.attrs[..], "macro_reexport") {
1252-
gate_feature_post!(&self, macro_reexport, i.span,
1251+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") {
1252+
gate_feature_post!(&self, macro_reexport, attr.span,
12531253
"macros reexports are experimental \
12541254
and possibly buggy");
12551255
}
@@ -1276,36 +1276,32 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
12761276
function may change over time, for now \
12771277
a top-level `fn main()` is required");
12781278
}
1279-
if attr::contains_name(&i.attrs[..], "must_use") {
1280-
gate_feature_post!(&self, fn_must_use, i.span,
1279+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
1280+
gate_feature_post!(&self, fn_must_use, attr.span,
12811281
"`#[must_use]` on functions is experimental",
12821282
GateStrength::Soft);
12831283
}
12841284
}
12851285

12861286
ast::ItemKind::Struct(..) => {
1287-
if attr::contains_name(&i.attrs[..], "simd") {
1288-
gate_feature_post!(&self, simd, i.span,
1287+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "simd") {
1288+
gate_feature_post!(&self, simd, attr.span,
12891289
"SIMD types are experimental and possibly buggy");
1290-
self.context.parse_sess.span_diagnostic.span_warn(i.span,
1290+
self.context.parse_sess.span_diagnostic.span_warn(attr.span,
12911291
"the `#[simd]` attribute \
12921292
is deprecated, use \
12931293
`#[repr(simd)]` instead");
12941294
}
1295-
for attr in &i.attrs {
1296-
if attr.path == "repr" {
1297-
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1298-
if item.check_name("simd") {
1299-
gate_feature_post!(&self, repr_simd, i.span,
1300-
"SIMD types are experimental \
1301-
and possibly buggy");
1302-
1303-
}
1304-
if item.check_name("align") {
1305-
gate_feature_post!(&self, repr_align, i.span,
1306-
"the struct `#[repr(align(u16))]` attribute \
1307-
is experimental");
1308-
}
1295+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "repr") {
1296+
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1297+
if item.check_name("simd") {
1298+
gate_feature_post!(&self, repr_simd, attr.span,
1299+
"SIMD types are experimental and possibly buggy");
1300+
}
1301+
if item.check_name("align") {
1302+
gate_feature_post!(&self, repr_align, attr.span,
1303+
"the struct `#[repr(align(u16))]` attribute \
1304+
is experimental");
13091305
}
13101306
}
13111307
}
@@ -1334,8 +1330,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
13341330

13351331
for impl_item in impl_items {
13361332
if let ast::ImplItemKind::Method(..) = impl_item.node {
1337-
if attr::contains_name(&impl_item.attrs[..], "must_use") {
1338-
gate_feature_post!(&self, fn_must_use, impl_item.span,
1333+
if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") {
1334+
gate_feature_post!(&self, fn_must_use, attr.span,
13391335
"`#[must_use]` on methods is experimental",
13401336
GateStrength::Soft);
13411337
}

src/test/compile-fail-fulldeps/gated-macro-reexports.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
#![crate_type = "dylib"]
1717

1818
#[macro_reexport(reexported)]
19+
//~^ ERROR macros reexports are experimental and possibly buggy
1920
#[macro_use] #[no_link]
2021
extern crate macro_reexport_1;
21-
//~^ ERROR macros reexports are experimental and possibly buggy

src/test/compile-fail/feature-gate-fn_must_use.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
struct MyStruct;
1414

1515
impl MyStruct {
16-
#[must_use]
17-
fn need_to_use_method() -> bool { true } //~ WARN `#[must_use]` on methods is experimental
16+
#[must_use] //~ WARN `#[must_use]` on methods is experimental
17+
fn need_to_use_method() -> bool { true }
1818
}
1919

20-
#[must_use]
21-
fn need_to_use_it() -> bool { true } //~ WARN `#[must_use]` on functions is experimental
20+
#[must_use] //~ WARN `#[must_use]` on functions is experimental
21+
fn need_to_use_it() -> bool { true }
2222

2323

2424
// Feature gates are tidy-required to have a specially named (or

src/test/compile-fail/feature-gate-repr-simd.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[repr(simd)]
12-
struct Foo(u64, u64); //~ error: SIMD types are experimental
11+
#[repr(simd)] //~ error: SIMD types are experimental
12+
struct Foo(u64, u64);
1313

1414
fn main() {}

src/test/compile-fail/feature-gate-repr_align.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010
#![feature(attr_literals)]
1111

12-
#[repr(align(64))]
13-
struct Foo(u64, u64); //~ error: the struct `#[repr(align(u16))]` attribute is experimental
12+
#[repr(align(64))] //~ error: the struct `#[repr(align(u16))]` attribute is experimental
13+
struct Foo(u64, u64);
1414

1515
fn main() {}

src/test/compile-fail/feature-gate-simd.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111

1212
// pretty-expanded FIXME #23616
1313

14-
#[repr(simd)]
14+
#[repr(simd)] //~ ERROR SIMD types are experimental
1515
struct RGBA {
1616
r: f32,
1717
g: f32,
1818
b: f32,
1919
a: f32
2020
}
21-
//~^^^^^^ ERROR SIMD types are experimental and possibly buggy (see issue #27731)
2221

2322
pub fn main() {}

src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,7 @@ mod repr {
354354
#[repr = "3900"] fn f() { }
355355
//~^ WARN unused attribute
356356

357-
#[repr = "3900"] struct S;
358-
//~^ WARN unused attribute
357+
struct S;
359358

360359
#[repr = "3900"] type T = S;
361360
//~^ WARN unused attribute
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(attr_literals)]
12+
13+
#[repr(align(16))]
14+
struct Gem {
15+
mohs_hardness: u8,
16+
poofed: bool,
17+
weapon: Weapon,
18+
}
19+
20+
#[repr(simd)]
21+
struct Weapon {
22+
name: String,
23+
damage: u32
24+
}
25+
26+
impl Gem {
27+
#[must_use] fn summon_weapon(&self) -> Weapon { self.weapon }
28+
}
29+
30+
#[must_use]
31+
fn bubble(gem: Gem) -> Result<Gem, ()> {
32+
if gem.poofed {
33+
Ok(gem)
34+
} else {
35+
Err(())
36+
}
37+
}
38+
39+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: the struct `#[repr(align(u16))]` attribute is experimental (see issue #33626)
2+
--> $DIR/gated-features-attr-spans.rs:13:1
3+
|
4+
13 | #[repr(align(16))]
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add #![feature(repr_align)] to the crate attributes to enable
8+
9+
error: SIMD types are experimental and possibly buggy (see issue #27731)
10+
--> $DIR/gated-features-attr-spans.rs:20:1
11+
|
12+
20 | #[repr(simd)]
13+
| ^^^^^^^^^^^^^
14+
|
15+
= help: add #![feature(repr_simd)] to the crate attributes to enable
16+
17+
warning: `#[must_use]` on methods is experimental (see issue #43302)
18+
--> $DIR/gated-features-attr-spans.rs:27:5
19+
|
20+
27 | #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon }
21+
| ^^^^^^^^^^^
22+
|
23+
= help: add #![feature(fn_must_use)] to the crate attributes to enable
24+
25+
warning: `#[must_use]` on functions is experimental (see issue #43302)
26+
--> $DIR/gated-features-attr-spans.rs:30:1
27+
|
28+
30 | #[must_use]
29+
| ^^^^^^^^^^^
30+
|
31+
= help: add #![feature(fn_must_use)] to the crate attributes to enable
32+
33+
error: aborting due to 2 previous errors
34+

0 commit comments

Comments
 (0)