Skip to content

Commit faf477a

Browse files
committed
Auto merge of #44111 - zackmdavis:feature_attr_error_span, r=nikomatsakis
feature error span on attribute for fn_must_use, SIMD/align reprs, 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.) ![feature_attr_error_span](https://user-images.githubusercontent.com/1076988/29746531-fd700bfe-8a91-11e7-9c5b-6f5324083887.png)
2 parents 6f82dea + 8bb2946 commit faf477a

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
@@ -1252,8 +1252,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
12521252
fn visit_item(&mut self, i: &'a ast::Item) {
12531253
match i.node {
12541254
ast::ItemKind::ExternCrate(_) => {
1255-
if attr::contains_name(&i.attrs[..], "macro_reexport") {
1256-
gate_feature_post!(&self, macro_reexport, i.span,
1255+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") {
1256+
gate_feature_post!(&self, macro_reexport, attr.span,
12571257
"macros reexports are experimental \
12581258
and possibly buggy");
12591259
}
@@ -1280,36 +1280,32 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
12801280
function may change over time, for now \
12811281
a top-level `fn main()` is required");
12821282
}
1283-
if attr::contains_name(&i.attrs[..], "must_use") {
1284-
gate_feature_post!(&self, fn_must_use, i.span,
1283+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
1284+
gate_feature_post!(&self, fn_must_use, attr.span,
12851285
"`#[must_use]` on functions is experimental",
12861286
GateStrength::Soft);
12871287
}
12881288
}
12891289

12901290
ast::ItemKind::Struct(..) => {
1291-
if attr::contains_name(&i.attrs[..], "simd") {
1292-
gate_feature_post!(&self, simd, i.span,
1291+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "simd") {
1292+
gate_feature_post!(&self, simd, attr.span,
12931293
"SIMD types are experimental and possibly buggy");
1294-
self.context.parse_sess.span_diagnostic.span_warn(i.span,
1294+
self.context.parse_sess.span_diagnostic.span_warn(attr.span,
12951295
"the `#[simd]` attribute \
12961296
is deprecated, use \
12971297
`#[repr(simd)]` instead");
12981298
}
1299-
for attr in &i.attrs {
1300-
if attr.path == "repr" {
1301-
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1302-
if item.check_name("simd") {
1303-
gate_feature_post!(&self, repr_simd, i.span,
1304-
"SIMD types are experimental \
1305-
and possibly buggy");
1306-
1307-
}
1308-
if item.check_name("align") {
1309-
gate_feature_post!(&self, repr_align, i.span,
1310-
"the struct `#[repr(align(u16))]` attribute \
1311-
is experimental");
1312-
}
1299+
if let Some(attr) = attr::find_by_name(&i.attrs[..], "repr") {
1300+
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1301+
if item.check_name("simd") {
1302+
gate_feature_post!(&self, repr_simd, attr.span,
1303+
"SIMD types are experimental and possibly buggy");
1304+
}
1305+
if item.check_name("align") {
1306+
gate_feature_post!(&self, repr_align, attr.span,
1307+
"the struct `#[repr(align(u16))]` attribute \
1308+
is experimental");
13131309
}
13141310
}
13151311
}
@@ -1338,8 +1334,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
13381334

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

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)