Add hard error and migration lint for unsafe attrs · rust-lang/rust@a23917c (original) (raw)

`@@ -5,21 +5,73 @@ use crate::{errors, parse_in};

`

5

5

`use rustc_ast::token::Delimiter;

`

6

6

`use rustc_ast::tokenstream::DelimSpan;

`

7

7

`use rustc_ast::MetaItemKind;

`

8

``

`-

use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem};

`

``

8

`+

use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, Safety};

`

9

9

`use rustc_errors::{Applicability, FatalError, PResult};

`

10

``

`-

use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};

`

``

10

`+

use rustc_feature::{

`

``

11

`+

AttributeSafety, AttributeTemplate, BuiltinAttribute, Features, BUILTIN_ATTRIBUTE_MAP,

`

``

12

`+

};

`

11

13

`use rustc_session::errors::report_lit_error;

`

12

``

`-

use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;

`

``

14

`+

use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};

`

13

15

`use rustc_session::lint::BuiltinLintDiag;

`

14

16

`use rustc_session::parse::ParseSess;

`

15

``

`-

use rustc_span::{sym, Span, Symbol};

`

``

17

`+

use rustc_span::{sym, BytePos, Span, Symbol};

`

16

18

``

17

``

`-

pub fn check_attr(psess: &ParseSess, attr: &Attribute) {

`

``

19

`+

pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {

`

18

20

`if attr.is_doc_comment() {

`

19

21

`return;

`

20

22

`}

`

21

23

``

22

24

`let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));

`

``

25

`+

let attr_item = attr.get_normal_item();

`

``

26

+

``

27

`+

let is_unsafe_attr = attr_info.is_some_and(|attr| attr.safety == AttributeSafety::Unsafe);

`

``

28

+

``

29

`+

if features.unsafe_attributes {

`

``

30

`+

if is_unsafe_attr {

`

``

31

`+

if let ast::Safety::Default = attr_item.unsafety {

`

``

32

`+

let path_span = attr_item.path.span;

`

``

33

+

``

34

`` +

// If the attr_item's span is not from a macro, then just suggest

``

``

35

`` +

// wrapping it in unsafe(...). Otherwise, we suggest putting the

``

``

36

`` +

// unsafe(, ) right after and right before the opening and closing

``

``

37

`+

// square bracket respectively.

`

``

38

`+

let diag_span = if attr_item.span().can_be_used_for_suggestions() {

`

``

39

`+

attr_item.span()

`

``

40

`+

} else {

`

``

41

`+

attr.span

`

``

42

`+

.with_lo(attr.span.lo() + BytePos(2))

`

``

43

`+

.with_hi(attr.span.hi() - BytePos(1))

`

``

44

`+

};

`

``

45

+

``

46

`+

if attr.span.at_least_rust_2024() {

`

``

47

`+

psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {

`

``

48

`+

span: path_span,

`

``

49

`+

suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {

`

``

50

`+

left: diag_span.shrink_to_lo(),

`

``

51

`+

right: diag_span.shrink_to_hi(),

`

``

52

`+

},

`

``

53

`+

});

`

``

54

`+

} else {

`

``

55

`+

psess.buffer_lint(

`

``

56

`+

UNSAFE_ATTR_OUTSIDE_UNSAFE,

`

``

57

`+

path_span,

`

``

58

`+

ast::CRATE_NODE_ID,

`

``

59

`+

BuiltinLintDiag::UnsafeAttrOutsideUnsafe {

`

``

60

`+

attribute_name_span: path_span,

`

``

61

`+

sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),

`

``

62

`+

},

`

``

63

`+

);

`

``

64

`+

}

`

``

65

`+

}

`

``

66

`+

} else {

`

``

67

`+

if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {

`

``

68

`+

psess.dcx().emit_err(errors::InvalidAttrUnsafe {

`

``

69

`+

span: unsafe_span,

`

``

70

`+

name: attr_item.path.clone(),

`

``

71

`+

});

`

``

72

`+

}

`

``

73

`+

}

`

``

74

`+

}

`

23

75

``

24

76

`// Check input tokens for built-in and key-value attributes.

`

25

77

`match attr_info {

`

`@@ -32,7 +84,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {

`

32

84

`}

`

33

85

`}

`

34

86

`}

`

35

``

`-

_ if let AttrArgs::Eq(..) = attr.get_normal_item().args => {

`

``

87

`+

_ if let AttrArgs::Eq(..) = attr_item.args => {

`

36

88

`// All key-value attributes are restricted to meta-item syntax.

`

37

89

`match parse_meta(psess, attr) {

`

38

90

`Ok(_) => {}

`