use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability, DiagnosticMessage};
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
use rustc_middle::ty::subst::SubstsRef;
// overflowing and only by 1.
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| {
- let mut err = lint.build(&format!("range endpoint is out of range for `{}`", ty));
+ let mut err = lint.build(fluent::lint::range_endpoint_out_of_range);
+ err.set_arg("ty", ty);
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
use ast::{LitIntType, LitKind};
// We need to preserve the literal's suffix,
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
err.span_suggestion(
parent_expr.span,
- "use an inclusive range instead",
+ fluent::lint::suggestion,
suggestion,
Applicability::MachineApplicable,
);
(t.name_str(), actually.to_string())
}
};
- let mut err = lint.build(&format!("literal out of range for `{}`", t));
+ let mut err = lint.build(fluent::lint::overflowing_bin_hex);
if negative {
// If the value is negative,
// emits a note about the value itself, apart from the literal.
- err.note(&format!(
- "the literal `{}` (decimal `{}`) does not fit into \
- the type `{}`",
- repr_str, val, t
- ));
- err.note(&format!("and the value `-{}` will become `{}{}`", repr_str, actually, t));
+ err.note(fluent::lint::negative_note);
+ err.note(fluent::lint::negative_becomes_note);
} else {
- err.note(&format!(
- "the literal `{}` (decimal `{}`) does not fit into \
- the type `{}` and will become `{}{}`",
- repr_str, val, t, actually, t
- ));
+ err.note(fluent::lint::positive_note);
}
if let Some(sugg_ty) =
get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
{
+ err.set_arg("suggestion_ty", sugg_ty);
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
err.span_suggestion(
expr.span,
- &format!("consider using the type `{}` instead", sugg_ty),
+ fluent::lint::suggestion,
format!("{}{}", sans_suffix, sugg_ty),
Applicability::MachineApplicable,
);
} else {
- err.help(&format!("consider using the type `{}` instead", sugg_ty));
+ err.help(fluent::lint::help);
}
}
+ err.set_arg("ty", t);
+ err.set_arg("lit", repr_str);
+ err.set_arg("dec", val);
+ err.set_arg("actually", actually);
err.emit();
});
}
}
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
- let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str()));
- err.note(&format!(
- "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`",
+ let mut err = lint.build(fluent::lint::overflowing_int);
+ err.set_arg("ty", t.name_str());
+ err.set_arg(
+ "lit",
cx.sess()
.source_map()
.span_to_snippet(lit.span)
.expect("must get snippet from literal"),
- t.name_str(),
- min,
- max,
- ));
+ );
+ err.set_arg("min", min);
+ err.set_arg("max", max);
+ err.note(fluent::lint::note);
if let Some(sugg_ty) =
get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
{
- err.help(&format!("consider using the type `{}` instead", sugg_ty));
+ err.set_arg("suggestion_ty", sugg_ty);
+ err.help(fluent::lint::help);
}
err.emit();
});
hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
- lint.build("only `u8` can be cast into `char`")
+ lint.build(fluent::lint::only_cast_u8_to_char)
.span_suggestion(
par_e.span,
- "use a `char` literal instead",
+ fluent::lint::suggestion,
format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable,
)
return;
}
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
- lint.build(&format!("literal out of range for `{}`", t.name_str()))
- .note(&format!(
- "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`",
+ lint.build(fluent::lint::overflowing_uint)
+ .set_arg("ty", t.name_str())
+ .set_arg(
+ "lit",
cx.sess()
.source_map()
.span_to_snippet(lit.span)
.expect("must get snippet from literal"),
- t.name_str(),
- min,
- max,
- ))
+ )
+ .set_arg("min", min)
+ .set_arg("max", max)
+ .note(fluent::lint::note)
.emit();
});
}
};
if is_infinite == Ok(true) {
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
- lint.build(&format!("literal out of range for `{}`", t.name_str()))
- .note(&format!(
- "the literal `{}` does not fit into the type `{}` and will be converted to `{}::INFINITY`",
+ lint.build(fluent::lint::overflowing_literal)
+ .set_arg("ty", t.name_str())
+ .set_arg(
+ "lit",
cx.sess()
.source_map()
.span_to_snippet(lit.span)
.expect("must get snippet from literal"),
- t.name_str(),
- t.name_str(),
- ))
+ )
+ .note(fluent::lint::note)
.emit();
});
}
hir::ExprKind::Binary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| {
- lint.build("comparison is useless due to type limits").emit();
+ lint.build(fluent::lint::unused_comparisons).emit();
});
}
}
enum FfiResult<'tcx> {
FfiSafe,
FfiPhantom(Ty<'tcx>),
- FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
+ FfiUnsafe { ty: Ty<'tcx>, reason: DiagnosticMessage, help: Option<DiagnosticMessage> },
}
pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
self.emit_ffi_unsafe_type_lint(
ty,
sp,
- "passing raw arrays by value is not FFI-safe",
- Some("consider passing a pointer to the array"),
+ fluent::lint::improper_ctypes_array_reason,
+ Some(fluent::lint::improper_ctypes_array_help),
);
true
} else {
} else {
// All fields are ZSTs; this means that the type should behave
// like (), which is FFI-unsafe
- FfiUnsafe {
- ty,
- reason: "this struct contains only zero-sized fields".into(),
- help: None,
- }
+ FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None }
}
} else {
// We can't completely trust repr(C) markings; make sure the fields are
FfiPhantom(..) if def.is_enum() => {
return FfiUnsafe {
ty,
- reason: "this enum contains a PhantomData field".into(),
+ reason: fluent::lint::improper_ctypes_enum_phantomdata,
help: None,
};
}
} else {
return FfiUnsafe {
ty,
- reason: "box cannot be represented as a single pointer".to_string(),
+ reason: fluent::lint::improper_ctypes_box,
help: None,
};
}
}
match def.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
- let kind = if def.is_struct() { "struct" } else { "union" };
-
if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe {
ty,
- reason: format!("this {} has unspecified layout", kind),
- help: Some(format!(
- "consider adding a `#[repr(C)]` or \
- `#[repr(transparent)]` attribute to this {}",
- kind
- )),
+ reason: if def.is_struct() {
+ fluent::lint::improper_ctypes_struct_layout_reason
+ } else {
+ fluent::lint::improper_ctypes_union_layout_reason
+ },
+ help: if def.is_struct() {
+ Some(fluent::lint::improper_ctypes_struct_layout_help)
+ } else {
+ Some(fluent::lint::improper_ctypes_union_layout_help)
+ },
};
}
if is_non_exhaustive && !def.did().is_local() {
return FfiUnsafe {
ty,
- reason: format!("this {} is non-exhaustive", kind),
+ reason: if def.is_struct() {
+ fluent::lint::improper_ctypes_struct_non_exhaustive
+ } else {
+ fluent::lint::improper_ctypes_union_non_exhaustive
+ },
help: None,
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe {
ty,
- reason: format!("this {} has no fields", kind),
- help: Some(format!("consider adding a member to this {}", kind)),
+ reason: if def.is_struct() {
+ fluent::lint::improper_ctypes_struct_fieldless_reason
+ } else {
+ fluent::lint::improper_ctypes_union_fieldless_reason
+ },
+ help: if def.is_struct() {
+ Some(fluent::lint::improper_ctypes_struct_fieldless_help)
+ } else {
+ Some(fluent::lint::improper_ctypes_union_fieldless_help)
+ },
};
}
if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
return FfiUnsafe {
ty,
- reason: "enum has no representation hint".into(),
- help: Some(
- "consider adding a `#[repr(C)]`, \
- `#[repr(transparent)]`, or integer `#[repr(...)]` \
- attribute to this enum"
- .into(),
- ),
+ reason: fluent::lint::improper_ctypes_enum_repr_reason,
+ help: Some(fluent::lint::improper_ctypes_enum_repr_help),
};
}
}
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
return FfiUnsafe {
ty,
- reason: "this enum is non-exhaustive".into(),
+ reason: fluent::lint::improper_ctypes_non_exhaustive,
help: None,
};
}
if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe {
ty,
- reason: "this enum has non-exhaustive variants".into(),
+ reason: fluent::lint::improper_ctypes_non_exhaustive_variant,
help: None,
};
}
ty::Char => FfiUnsafe {
ty,
- reason: "the `char` type has no C equivalent".into(),
- help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
+ reason: fluent::lint::improper_ctypes_char_reason,
+ help: Some(fluent::lint::improper_ctypes_char_help),
},
- ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe {
- ty,
- reason: "128-bit integers don't currently have a known stable ABI".into(),
- help: None,
- },
+ ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
+ FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None }
+ }
// Primitive types with a stable representation.
ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
ty::Slice(_) => FfiUnsafe {
ty,
- reason: "slices have no C equivalent".into(),
- help: Some("consider using a raw pointer instead".into()),
+ reason: fluent::lint::improper_ctypes_slice_reason,
+ help: Some(fluent::lint::improper_ctypes_slice_help),
},
ty::Dynamic(..) => {
- FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None }
+ FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None }
}
ty::Str => FfiUnsafe {
ty,
- reason: "string slices have no C equivalent".into(),
- help: Some("consider using `*const u8` and a length instead".into()),
+ reason: fluent::lint::improper_ctypes_str_reason,
+ help: Some(fluent::lint::improper_ctypes_str_help),
},
ty::Tuple(..) => FfiUnsafe {
ty,
- reason: "tuples have unspecified layout".into(),
- help: Some("consider using a struct instead".into()),
+ reason: fluent::lint::improper_ctypes_tuple_reason,
+ help: Some(fluent::lint::improper_ctypes_tuple_help),
},
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
if self.is_internal_abi(sig.abi()) {
return FfiUnsafe {
ty,
- reason: "this function pointer has Rust-specific calling convention".into(),
- help: Some(
- "consider using an `extern fn(...) -> ...` \
- function pointer instead"
- .into(),
- ),
+ reason: fluent::lint::improper_ctypes_fnptr_reason,
+ help: Some(fluent::lint::improper_ctypes_fnptr_help),
};
}
// While opaque types are checked for earlier, if a projection in a struct field
// normalizes to an opaque type, then it will reach this branch.
ty::Opaque(..) => {
- FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
+ FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None }
}
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
&mut self,
ty: Ty<'tcx>,
sp: Span,
- note: &str,
- help: Option<&str>,
+ note: DiagnosticMessage,
+ help: Option<DiagnosticMessage>,
) {
let lint = match self.mode {
CItemKind::Declaration => IMPROPER_CTYPES,
CItemKind::Declaration => "block",
CItemKind::Definition => "fn",
};
- let mut diag = lint.build(&format!(
- "`extern` {} uses type `{}`, which is not FFI-safe",
- item_description, ty
- ));
- diag.span_label(sp, "not FFI-safe");
+ let mut diag = lint.build(fluent::lint::improper_ctypes);
+ diag.set_arg("ty", ty);
+ diag.set_arg("desc", item_description);
+ diag.span_label(sp, fluent::lint::label);
if let Some(help) = help {
diag.help(help);
}
diag.note(note);
if let ty::Adt(def, _) = ty.kind() {
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
- diag.span_note(sp, "the type is defined here");
+ diag.span_note(sp, fluent::lint::note);
}
}
diag.emit();
}
if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() {
- self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
+ self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None);
true
} else {
false
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {
- self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
+ self.emit_ffi_unsafe_type_lint(
+ ty,
+ sp,
+ fluent::lint::improper_ctypes_only_phantomdata,
+ None,
+ );
}
// If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
// argument, which after substitution, is `()`, then this branch can be hit.
FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
FfiResult::FfiUnsafe { ty, reason, help } => {
- self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref());
+ self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
}
}
}
VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span,
|lint| {
- lint.build(&format!(
- "enum variant is more than three times \
- larger ({} bytes) than the next largest",
- largest
- ))
- .emit();
+ lint.build(fluent::lint::variant_size_differences)
+ .set_arg("largest", largest)
+ .emit();
},
);
}
None
}
- fn matches_ordering(cx: &LateContext<'_>, did: DefId, orderings: &[Symbol]) -> bool {
+ fn match_ordering(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<Symbol> {
+ let ExprKind::Path(ref ord_qpath) = ord_arg.kind else { return None };
+ let did = cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()?;
let tcx = cx.tcx;
let atomic_ordering = tcx.get_diagnostic_item(sym::Ordering);
- orderings.iter().any(|ordering| {
- tcx.item_name(did) == *ordering && {
- let parent = tcx.parent(did);
- Some(parent) == atomic_ordering
- // needed in case this is a ctor, not a variant
- || tcx.opt_parent(parent) == atomic_ordering
- }
- })
- }
-
- fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> {
- if let ExprKind::Path(ref ord_qpath) = ord_arg.kind {
- cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()
- } else {
- None
- }
+ let name = tcx.item_name(did);
+ let parent = tcx.parent(did);
+ [sym::Relaxed, sym::Release, sym::Acquire, sym::AcqRel, sym::SeqCst].into_iter().find(
+ |&ordering| {
+ name == ordering
+ && (Some(parent) == atomic_ordering
+ // needed in case this is a ctor, not a variant
+ || tcx.opt_parent(parent) == atomic_ordering)
+ },
+ )
}
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
- use rustc_hir::def::{DefKind, Res};
- use rustc_hir::QPath;
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
&& let Some((ordering_arg, invalid_ordering)) = match method {
sym::load => Some((&args[1], sym::Release)),
sym::store => Some((&args[2], sym::Acquire)),
_ => None,
}
- && let ExprKind::Path(QPath::Resolved(_, path)) = ordering_arg.kind
- && let Res::Def(DefKind::Ctor(..), ctor_id) = path.res
- && Self::matches_ordering(cx, ctor_id, &[invalid_ordering, sym::AcqRel])
+ && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
+ && (ordering == invalid_ordering || ordering == sym::AcqRel)
{
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
if method == sym::load {
- diag.build("atomic loads cannot have `Release` or `AcqRel` ordering")
- .help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`")
+ diag.build(fluent::lint::atomic_ordering_load)
+ .help(fluent::lint::help)
.emit()
} else {
debug_assert_eq!(method, sym::store);
- diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering")
- .help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`")
+ diag.build(fluent::lint::atomic_ordering_store)
+ .help(fluent::lint::help)
.emit();
}
});
&& let ExprKind::Path(ref func_qpath) = func.kind
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
- && let ExprKind::Path(ref ordering_qpath) = &args[0].kind
- && let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id()
- && Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed])
+ && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
{
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
- diag.build("memory fences cannot have `Relaxed` ordering")
- .help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`")
+ diag.build(fluent::lint::atomic_ordering_fence)
+ .help(fluent::lint::help)
.emit();
});
}
}
fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak])
- && let Some((success_order_arg, failure_order_arg)) = match method {
- sym::fetch_update => Some((&args[1], &args[2])),
- sym::compare_exchange | sym::compare_exchange_weak => Some((&args[3], &args[4])),
- _ => None,
- }
- && let Some(fail_ordering_def_id) = Self::opt_ordering_defid(cx, failure_order_arg)
- {
- // Helper type holding on to some checking and error reporting data. Has
- // - (success ordering,
- // - list of failure orderings forbidden by the success order,
- // - suggestion message)
- type OrdLintInfo = (Symbol, &'static [Symbol], &'static str);
- const RELAXED: OrdLintInfo = (sym::Relaxed, &[sym::SeqCst, sym::Acquire], "ordering mode `Relaxed`");
- const ACQUIRE: OrdLintInfo = (sym::Acquire, &[sym::SeqCst], "ordering modes `Acquire` or `Relaxed`");
- const SEQ_CST: OrdLintInfo = (sym::SeqCst, &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
- const RELEASE: OrdLintInfo = (sym::Release, RELAXED.1, RELAXED.2);
- const ACQREL: OrdLintInfo = (sym::AcqRel, ACQUIRE.1, ACQUIRE.2);
- const SEARCH: [OrdLintInfo; 5] = [RELAXED, ACQUIRE, SEQ_CST, RELEASE, ACQREL];
-
- let success_lint_info = Self::opt_ordering_defid(cx, success_order_arg)
- .and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
- SEARCH
- .iter()
- .copied()
- .find(|(ordering, ..)| {
- Self::matches_ordering(cx, success_ord_def_id, &[*ordering])
- })
- });
- if Self::matches_ordering(cx, fail_ordering_def_id, &[sym::Release, sym::AcqRel]) {
- // If we don't know the success order is, use what we'd suggest
- // if it were maximally permissive.
- let suggested = success_lint_info.unwrap_or(SEQ_CST).2;
- cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
- let msg = format!(
- "{}'s failure ordering may not be `Release` or `AcqRel`",
- method,
- );
- diag.build(&msg)
- .help(&format!("consider using {} instead", suggested))
- .emit();
- });
- } else if let Some((success_ord, bad_ords_given_success, suggested)) = success_lint_info {
- if Self::matches_ordering(cx, fail_ordering_def_id, bad_ords_given_success) {
- cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
- let msg = format!(
- "{}'s failure ordering may not be stronger than the success ordering of `{}`",
- method,
- success_ord,
- );
- diag.build(&msg)
- .help(&format!("consider using {} instead", suggested))
- .emit();
- });
- }
- }
+ let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak])
+ else {return };
+
+ let (success_order_arg, fail_order_arg) = match method {
+ sym::fetch_update => (&args[1], &args[2]),
+ sym::compare_exchange | sym::compare_exchange_weak => (&args[3], &args[4]),
+ _ => return,
+ };
+
+ let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return };
+
+ if matches!(fail_ordering, sym::Release | sym::AcqRel) {
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg.span, |diag| {
+ diag.build(fluent::lint::atomic_ordering_invalid)
+ .set_arg("method", method)
+ .span_label(fail_order_arg.span, fluent::lint::label)
+ .help(fluent::lint::help)
+ .emit();
+ });
+ }
+
+ let Some(success_ordering) = Self::match_ordering(cx, success_order_arg) else { return };
+
+ if matches!(
+ (success_ordering, fail_ordering),
+ (sym::Relaxed | sym::Release, sym::Acquire)
+ | (sym::Relaxed | sym::Release | sym::Acquire | sym::AcqRel, sym::SeqCst)
+ ) {
+ let success_suggestion =
+ if success_ordering == sym::Release && fail_ordering == sym::Acquire {
+ sym::AcqRel
+ } else {
+ fail_ordering
+ };
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| {
+ diag.build(fluent::lint::atomic_ordering_invalid_fail_success)
+ .set_arg("method", method)
+ .set_arg("fail_ordering", fail_ordering)
+ .set_arg("success_ordering", success_ordering)
+ .set_arg("success_suggestion", success_suggestion)
+ .span_label(fail_order_arg.span, fluent::lint::fail_label)
+ .span_label(success_order_arg.span, fluent::lint::success_label)
+ .span_suggestion_short(
+ success_order_arg.span,
+ fluent::lint::suggestion,
+ format!("std::sync::atomic::Ordering::{success_suggestion}"),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ });
}
}
}