Skip to content

Commit bb6d372

Browse files
committed
Auto merge of rust-lang#126886 - workingjubilee:rollup-e6ar0vq, r=workingjubilee
Rollup of 9 pull requests Successful merges: - rust-lang#126177 (Add hard error and migration lint for unsafe attrs) - rust-lang#126298 (Promote loongarch64-unknown-linux-musl to Tier 2 with host tools) - rust-lang#126455 (For [E0308]: mismatched types, when expr is in an arm's body, not add semicolon ';' at the end of it.) - rust-lang#126754 (Implement `use<>` formatting in rustfmt) - rust-lang#126807 (std::unix::fs: copy simplification for apple.) - rust-lang#126845 (Weekly `cargo update`) - rust-lang#126849 (Fix 32-bit Arm reg classes by hierarchically sorting them) - rust-lang#126854 (std::unix::os::home_dir: fallback's optimisation.) - rust-lang#126861 (Migrate `run-make/invalid-library` to `rmake.rs`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents d49994b + 969bbc6 commit bb6d372

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1003
-286
lines changed

Cargo.lock

+57-128
Large diffs are not rendered by default.

compiler/rustc_ast_passes/src/ast_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
899899

900900
impl<'a> Visitor<'a> for AstValidator<'a> {
901901
fn visit_attribute(&mut self, attr: &Attribute) {
902-
validate_attr::check_attr(&self.session.psess, attr);
902+
validate_attr::check_attr(&self.features, &self.session.psess, attr);
903903
}
904904

905905
fn visit_ty(&mut self, ty: &'a Ty) {

compiler/rustc_expand/src/expand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1883,7 +1883,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
18831883
let mut span: Option<Span> = None;
18841884
while let Some(attr) = attrs.next() {
18851885
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
1886-
validate_attr::check_attr(&self.cx.sess.psess, attr);
1886+
validate_attr::check_attr(features, &self.cx.sess.psess, attr);
18871887

18881888
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
18891889
span = Some(current_span);

compiler/rustc_feature/src/builtin_attrs.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1145,10 +1145,6 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool {
11451145
})
11461146
}
11471147

1148-
pub fn is_unsafe_attr(name: Symbol) -> bool {
1149-
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe)
1150-
}
1151-
11521148
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
11531149
LazyLock::new(|| {
11541150
let mut map = FxHashMap::default();

compiler/rustc_feature/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub use accepted::ACCEPTED_FEATURES;
125125
pub use builtin_attrs::AttributeDuplicates;
126126
pub use builtin_attrs::{
127127
deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
128-
is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType,
128+
is_valid_for_get_attr, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
129129
BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
130130
};
131131
pub use removed::REMOVED_FEATURES;

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+51-9
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ use rustc_middle::lint::in_external_macro;
2626
use rustc_middle::middle::stability::EvalResult;
2727
use rustc_middle::span_bug;
2828
use rustc_middle::ty::print::with_no_trimmed_paths;
29-
use rustc_middle::ty::{
30-
self, suggest_constraining_type_params, Article, Binder, IsSuggestable, Ty, TypeVisitableExt,
31-
Upcast,
32-
};
29+
use rustc_middle::ty::{self, suggest_constraining_type_params, Article, Binder};
30+
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Upcast};
3331
use rustc_session::errors::ExprParenthesesNeeded;
3432
use rustc_span::source_map::Spanned;
3533
use rustc_span::symbol::{sym, Ident};
@@ -1111,12 +1109,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11111109
self.tcx.hir().span_with_body(self.tcx.local_def_id_to_hir_id(fn_id)),
11121110
)
11131111
{
1114-
err.multipart_suggestion(
1112+
// When the expr is in a match arm's body, we shouldn't add semicolon ';' at the end.
1113+
// For example:
1114+
// fn mismatch_types() -> i32 {
1115+
// match 1 {
1116+
// x => dbg!(x),
1117+
// }
1118+
// todo!()
1119+
// }
1120+
// -------------^^^^^^^-
1121+
// Don't add semicolon `;` at the end of `dbg!(x)` expr
1122+
fn is_in_arm<'tcx>(expr: &'tcx hir::Expr<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
1123+
for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
1124+
match node {
1125+
hir::Node::Block(block) => {
1126+
if let Some(ret) = block.expr
1127+
&& ret.hir_id == expr.hir_id
1128+
{
1129+
continue;
1130+
}
1131+
}
1132+
hir::Node::Arm(arm) => {
1133+
if let hir::ExprKind::Block(block, _) = arm.body.kind
1134+
&& let Some(ret) = block.expr
1135+
&& ret.hir_id == expr.hir_id
1136+
{
1137+
return true;
1138+
}
1139+
}
1140+
hir::Node::Expr(e) if let hir::ExprKind::Block(block, _) = e.kind => {
1141+
if let Some(ret) = block.expr
1142+
&& ret.hir_id == expr.hir_id
1143+
{
1144+
continue;
1145+
}
1146+
}
1147+
_ => {
1148+
return false;
1149+
}
1150+
}
1151+
}
1152+
1153+
false
1154+
}
1155+
let mut suggs = vec![(span.shrink_to_lo(), "return ".to_string())];
1156+
if !is_in_arm(expr, self.tcx) {
1157+
suggs.push((span.shrink_to_hi(), ";".to_string()));
1158+
}
1159+
err.multipart_suggestion_verbose(
11151160
"you might have meant to return this value",
1116-
vec![
1117-
(span.shrink_to_lo(), "return ".to_string()),
1118-
(span.shrink_to_hi(), ";".to_string()),
1119-
],
1161+
suggs,
11201162
Applicability::MaybeIncorrect,
11211163
);
11221164
}

compiler/rustc_lint/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,10 @@ lint_unnameable_test_items = cannot test inner items
825825
lint_unnecessary_qualification = unnecessary qualification
826826
.suggestion = remove the unnecessary path segments
827827
828+
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
829+
.label = usage of unsafe attribute
830+
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
831+
828832
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
829833
830834
lint_untranslatable_diag = diagnostics should be created using translatable messages

compiler/rustc_lint/src/context/diagnostics.rs

+10
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,16 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
319319
BuiltinLintDiag::UnusedQualifications { removal_span } => {
320320
lints::UnusedQualifications { removal_span }.decorate_lint(diag);
321321
}
322+
BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
323+
attribute_name_span,
324+
sugg_spans: (left, right),
325+
} => {
326+
lints::UnsafeAttrOutsideUnsafe {
327+
span: attribute_name_span,
328+
suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right },
329+
}
330+
.decorate_lint(diag);
331+
}
322332
BuiltinLintDiag::AssociatedConstElidedLifetime {
323333
elided,
324334
span: lt_span,

compiler/rustc_lint/src/lints.rs

+21
Original file line numberDiff line numberDiff line change
@@ -2890,3 +2890,24 @@ pub struct RedundantImportVisibility {
28902890
pub import_vis: String,
28912891
pub max_vis: String,
28922892
}
2893+
2894+
#[derive(LintDiagnostic)]
2895+
#[diag(lint_unsafe_attr_outside_unsafe)]
2896+
pub struct UnsafeAttrOutsideUnsafe {
2897+
#[label]
2898+
pub span: Span,
2899+
#[subdiagnostic]
2900+
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
2901+
}
2902+
2903+
#[derive(Subdiagnostic)]
2904+
#[multipart_suggestion(
2905+
lint_unsafe_attr_outside_unsafe_suggestion,
2906+
applicability = "machine-applicable"
2907+
)]
2908+
pub struct UnsafeAttrOutsideUnsafeSuggestion {
2909+
#[suggestion_part(code = "unsafe(")]
2910+
pub left: Span,
2911+
#[suggestion_part(code = ")")]
2912+
pub right: Span,
2913+
}

compiler/rustc_lint_defs/src/builtin.rs

+43
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ declare_lint_pass! {
115115
UNNAMEABLE_TYPES,
116116
UNREACHABLE_CODE,
117117
UNREACHABLE_PATTERNS,
118+
UNSAFE_ATTR_OUTSIDE_UNSAFE,
118119
UNSAFE_OP_IN_UNSAFE_FN,
119120
UNSTABLE_NAME_COLLISIONS,
120121
UNSTABLE_SYNTAX_PRE_EXPANSION,
@@ -4902,3 +4903,45 @@ declare_lint! {
49024903
reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>",
49034904
};
49044905
}
4906+
4907+
declare_lint! {
4908+
/// The `unsafe_attr_outside_unsafe` lint detects a missing unsafe keyword
4909+
/// on attributes considered unsafe.
4910+
///
4911+
/// ### Example
4912+
///
4913+
/// ```rust
4914+
/// #![feature(unsafe_attributes)]
4915+
/// #![warn(unsafe_attr_outside_unsafe)]
4916+
///
4917+
/// #[no_mangle]
4918+
/// extern "C" fn foo() {}
4919+
///
4920+
/// fn main() {}
4921+
/// ```
4922+
///
4923+
/// {{produces}}
4924+
///
4925+
/// ### Explanation
4926+
///
4927+
/// Some attributes (e.g. `no_mangle`, `export_name`, `link_section` -- see
4928+
/// [issue #82499] for a more complete list) are considered "unsafe" attributes.
4929+
/// An unsafe attribute must only be used inside unsafe(...).
4930+
///
4931+
/// This lint can automatically wrap the attributes in `unsafe(...)` , but this
4932+
/// obviously cannot verify that the preconditions of the `unsafe`
4933+
/// attributes are fulfilled, so that is still up to the user.
4934+
///
4935+
/// The lint is currently "allow" by default, but that might change in the
4936+
/// future.
4937+
///
4938+
/// [editions]: https://doc.rust-lang.org/edition-guide/
4939+
/// [issue #82499]: https://github.com/rust-lang/rust/issues/82499
4940+
pub UNSAFE_ATTR_OUTSIDE_UNSAFE,
4941+
Allow,
4942+
"detects unsafe attributes outside of unsafe",
4943+
@future_incompatible = FutureIncompatibleInfo {
4944+
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
4945+
reference: "issue #123757 <https://github.com/rust-lang/rust/issues/123757>",
4946+
};
4947+
}

compiler/rustc_lint_defs/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,10 @@ pub enum BuiltinLintDiag {
691691
/// The span of the unnecessarily-qualified path to remove.
692692
removal_span: Span,
693693
},
694+
UnsafeAttrOutsideUnsafe {
695+
attribute_name_span: Span,
696+
sugg_spans: (Span, Span),
697+
},
694698
AssociatedConstElidedLifetime {
695699
elided: bool,
696700
span: Span,

compiler/rustc_parse/messages.ftl

+9
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,10 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment
366366
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
367367
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
368368
369+
parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
370+
.suggestion = remove the `unsafe(...)`
371+
.note = extraneous unsafe is not allowed in attributes
372+
369373
parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
370374
.label = the `block` fragment is within this context
371375
.suggestion = wrap this in another block
@@ -866,6 +870,11 @@ parse_unmatched_angle_brackets = {$num_extra_brackets ->
866870
*[other] remove extra angle brackets
867871
}
868872
873+
parse_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
874+
.label = usage of unsafe attribute
875+
parse_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
876+
877+
869878
parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
870879
.label = {parse_unskipped_whitespace}
871880

compiler/rustc_parse/src/errors.rs

+31
Original file line numberDiff line numberDiff line change
@@ -2997,3 +2997,34 @@ pub(crate) struct DotDotRangeAttribute {
29972997
#[primary_span]
29982998
pub span: Span,
29992999
}
3000+
3001+
#[derive(Diagnostic)]
3002+
#[diag(parse_invalid_attr_unsafe)]
3003+
#[note]
3004+
pub struct InvalidAttrUnsafe {
3005+
#[primary_span]
3006+
pub span: Span,
3007+
pub name: Path,
3008+
}
3009+
3010+
#[derive(Diagnostic)]
3011+
#[diag(parse_unsafe_attr_outside_unsafe)]
3012+
pub struct UnsafeAttrOutsideUnsafe {
3013+
#[primary_span]
3014+
#[label]
3015+
pub span: Span,
3016+
#[subdiagnostic]
3017+
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
3018+
}
3019+
3020+
#[derive(Subdiagnostic)]
3021+
#[multipart_suggestion(
3022+
parse_unsafe_attr_outside_unsafe_suggestion,
3023+
applicability = "machine-applicable"
3024+
)]
3025+
pub struct UnsafeAttrOutsideUnsafeSuggestion {
3026+
#[suggestion_part(code = "unsafe(")]
3027+
pub left: Span,
3028+
#[suggestion_part(code = ")")]
3029+
pub right: Span,
3030+
}

compiler/rustc_parse/src/validate_attr.rs

+58-6
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,73 @@ use crate::{errors, parse_in};
55
use rustc_ast::token::Delimiter;
66
use rustc_ast::tokenstream::DelimSpan;
77
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};
99
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+
};
1113
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};
1315
use rustc_session::lint::BuiltinLintDiag;
1416
use rustc_session::parse::ParseSess;
15-
use rustc_span::{sym, Span, Symbol};
17+
use rustc_span::{sym, BytePos, Span, Symbol};
1618

17-
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
19+
pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
1820
if attr.is_doc_comment() {
1921
return;
2022
}
2123

2224
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+
}
2375

2476
// Check input tokens for built-in and key-value attributes.
2577
match attr_info {
@@ -32,7 +84,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
3284
}
3385
}
3486
}
35-
_ if let AttrArgs::Eq(..) = attr.get_normal_item().args => {
87+
_ if let AttrArgs::Eq(..) = attr_item.args => {
3688
// All key-value attributes are restricted to meta-item syntax.
3789
match parse_meta(psess, attr) {
3890
Ok(_) => {}

compiler/rustc_passes/messages.ftl

-4
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,6 @@ passes_invalid_attr_at_crate_level =
384384
passes_invalid_attr_at_crate_level_item =
385385
the inner attribute doesn't annotate this {$kind}
386386
387-
passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
388-
.suggestion = remove the `unsafe(...)`
389-
.note = extraneous unsafe is not allowed in attributes
390-
391387
passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
392388
393389
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments

0 commit comments

Comments
 (0)