]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_lint/src/builtin.rs
bump version to 1.79.0+dfsg1-1~bpo12+pve2
[rustc.git] / compiler / rustc_lint / src / builtin.rs
CommitLineData
c34b1796
AL
1//! Lints in the Rust compiler.
2//!
3//! This contains lints which can feasibly be implemented as their own
ba9703b0
XL
4//! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
5//! definitions of lints that are emitted directly inside the main compiler.
c34b1796
AL
6//!
7//! To add a new lint to rustc, declare it here using `declare_lint!()`.
8//! Then add code to emit the new lint in the appropriate circumstances.
9//! You can do that in an existing `LintPass` if it makes sense, or in a
10//! new `LintPass`, or using `Session::add_lint` elsewhere in the
11//! compiler. Only do the latter if the check can't be written cleanly as a
12//! `LintPass` (also, note that such lints will need to be defined in
ba9703b0 13//! `rustc_session::lint::builtin`, not here).
c34b1796 14//!
9fa01778
XL
15//! If you define a new `EarlyLintPass`, you will also need to add it to the
16//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
17//! `lib.rs`. Use the former for unit-like structs and the latter for structs
18//! with a `pub fn new()`.
19//!
20//! If you define a new `LateLintPass`, you will also need to add it to the
21//! `late_lint_methods!` invocation in `lib.rs`.
c34b1796 22
9ffffee4 23use crate::fluent_generated as fluent;
3dfed10e 24use crate::{
49aad941 25 errors::BuiltinEllipsisInclusiveRangePatterns,
9c376795 26 lints::{
add651ee
FG
27 BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle,
28 BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed,
29 BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
30 BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
31 BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
9c376795
FG
32 BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
33 BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
34 BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
35 BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
add651ee 36 BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
9c376795
FG
37 BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
38 BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
39 BuiltinWhileTrue, SuggestChangingAssocTypes,
40 },
add651ee 41 EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
3dfed10e 42};
74b04a01
XL
43use rustc_ast::tokenstream::{TokenStream, TokenTree};
44use rustc_ast::visit::{FnCtxt, FnKind};
3dfed10e 45use rustc_ast::{self as ast, *};
74b04a01 46use rustc_ast_pretty::pprust::{self, expr_to_string};
c620b35d 47use rustc_errors::{Applicability, LintDiagnostic, MultiSpan};
3c0e092e 48use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
dfeec247
XL
49use rustc_hir as hir;
50use rustc_hir::def::{DefKind, Res};
add651ee 51use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
487cf647 52use rustc_hir::intravisit::FnKind as HirFnKind;
add651ee 53use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin};
064997fb 54use rustc_middle::lint::in_external_macro;
add651ee 55use rustc_middle::ty::layout::LayoutOf;
1b1a35ee 56use rustc_middle::ty::print::with_no_trimmed_paths;
add651ee
FG
57use rustc_middle::ty::GenericArgKind;
58use rustc_middle::ty::ToPredicate;
49aad941 59use rustc_middle::ty::TypeVisitableExt;
add651ee 60use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
c620b35d 61use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason};
dfeec247
XL
62use rustc_span::edition::Edition;
63use rustc_span::source_map::Spanned;
f9f354fc 64use rustc_span::symbol::{kw, sym, Ident, Symbol};
04454e1e 65use rustc_span::{BytePos, InnerSpan, Span};
add651ee 66use rustc_target::abi::Abi;
9c376795 67use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
add651ee 68use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
9c376795 69use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
e9174d1e 70
dfeec247 71use crate::nonstandard_style::{method_context, MethodLateContext};
9fa01778 72
dfeec247 73use std::fmt::Write;
c34b1796 74
c620b35d 75// hardwired lints from rustc_lint_defs
dfeec247 76pub use rustc_session::lint::builtin::*;
c34b1796 77
b039eaaf 78declare_lint! {
1b1a35ee
XL
79 /// The `while_true` lint detects `while true { }`.
80 ///
81 /// ### Example
82 ///
83 /// ```rust,no_run
84 /// while true {
85 ///
86 /// }
87 /// ```
88 ///
89 /// {{produces}}
90 ///
91 /// ### Explanation
92 ///
93 /// `while true` should be replaced with `loop`. A `loop` expression is
94 /// the preferred way to write an infinite loop because it more directly
95 /// expresses the intent of the loop.
b039eaaf
SL
96 WHILE_TRUE,
97 Warn,
98 "suggest using `loop { }` instead of `while true { }`"
99}
c34b1796 100
532ac7d7 101declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
c34b1796 102
416331ca
XL
103/// Traverse through any amount of parenthesis and return the first non-parens expression.
104fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
e74abb32 105 while let ast::ExprKind::Paren(sub) = &expr.kind {
416331ca
XL
106 expr = sub;
107 }
108 expr
109}
110
111impl EarlyLintPass for WhileTrue {
9c376795 112 #[inline]
416331ca 113 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
2b03887a 114 if let ast::ExprKind::While(cond, _, label) = &e.kind
49aad941 115 && let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
487cf647
FG
116 && let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
117 && !cond.span.from_expansion()
2b03887a
FG
118 {
119 let condition_span = e.span.with_hi(cond.span.hi());
9c376795 120 let replace = format!(
ed00b5ec
FG
121 "{}loop",
122 label.map_or_else(String::new, |label| format!("{}: ", label.ident,))
123 );
c0240ec0 124 cx.emit_span_lint(
ed00b5ec
FG
125 WHILE_TRUE,
126 condition_span,
127 BuiltinWhileTrue { suggestion: condition_span, replace },
128 );
c34b1796
AL
129 }
130 }
131}
132
133declare_lint! {
1b1a35ee
XL
134 /// The `box_pointers` lints use of the Box type.
135 ///
136 /// ### Example
137 ///
138 /// ```rust,compile_fail
139 /// #![deny(box_pointers)]
140 /// struct Foo {
141 /// x: Box<isize>,
142 /// }
143 /// ```
144 ///
145 /// {{produces}}
146 ///
147 /// ### Explanation
148 ///
149 /// This lint is mostly historical, and not particularly useful. `Box<T>`
150 /// used to be built into the language, and the only way to do heap
151 /// allocation. Today's Rust can call into other allocators, etc.
b039eaaf
SL
152 BOX_POINTERS,
153 Allow,
154 "use of owned (Box type) heap memory"
c34b1796
AL
155}
156
532ac7d7 157declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
b039eaaf
SL
158
159impl BoxPointers {
5099ac24
FG
160 fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
161 for leaf in ty.walk() {
ed00b5ec
FG
162 if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
163 && leaf_ty.is_box()
164 {
c0240ec0 165 cx.emit_span_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
c34b1796
AL
166 }
167 }
168 }
169}
170
f035d41b
XL
171impl<'tcx> LateLintPass<'tcx> for BoxPointers {
172 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
e74abb32 173 match it.kind {
dfeec247
XL
174 hir::ItemKind::Fn(..)
175 | hir::ItemKind::TyAlias(..)
176 | hir::ItemKind::Enum(..)
177 | hir::ItemKind::Struct(..)
add651ee
FG
178 | hir::ItemKind::Union(..) => self.check_heap_type(
179 cx,
180 it.span,
181 cx.tcx.type_of(it.owner_id).instantiate_identity(),
182 ),
dfeec247 183 _ => (),
d9579d0f 184 }
d9579d0f 185
b039eaaf 186 // If it's a struct, we also have to check the fields' types
e74abb32 187 match it.kind {
dfeec247 188 hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
487cf647 189 for field in struct_def.fields() {
9ffffee4
FG
190 self.check_heap_type(
191 cx,
192 field.span,
add651ee 193 cx.tcx.type_of(field.def_id).instantiate_identity(),
9ffffee4 194 );
b039eaaf 195 }
d9579d0f 196 }
c30ab7b3 197 _ => (),
d9579d0f
AL
198 }
199 }
200
f035d41b 201 fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
3dfed10e 202 let ty = cx.typeck_results().node_type(e.hir_id);
b039eaaf 203 self.check_heap_type(cx, e.span, ty);
c34b1796
AL
204 }
205}
206
c34b1796 207declare_lint! {
1b1a35ee
XL
208 /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
209 /// instead of `Struct { x }` in a pattern.
210 ///
211 /// ### Example
212 ///
213 /// ```rust
214 /// struct Point {
215 /// x: i32,
216 /// y: i32,
217 /// }
218 ///
219 ///
220 /// fn main() {
221 /// let p = Point {
222 /// x: 5,
223 /// y: 5,
224 /// };
225 ///
226 /// match p {
227 /// Point { x: x, y: y } => (),
228 /// }
229 /// }
230 /// ```
231 ///
232 /// {{produces}}
233 ///
234 /// ### Explanation
235 ///
236 /// The preferred style is to avoid the repetition of specifying both the
237 /// field name and the binding name if both identifiers are the same.
c34b1796
AL
238 NON_SHORTHAND_FIELD_PATTERNS,
239 Warn,
abe05a73 240 "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
c34b1796
AL
241}
242
532ac7d7 243declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
c34b1796 244
f035d41b
XL
245impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
246 fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
dfeec247
XL
247 if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
248 let variant = cx
3dfed10e 249 .typeck_results()
dfeec247
XL
250 .pat_ty(pat)
251 .ty_adt_def()
252 .expect("struct pattern type is not an ADT")
f035d41b 253 .variant_of_res(cx.qpath_res(qpath, pat.hir_id));
3157f602 254 for fieldpat in field_pats {
e1599b0c 255 if fieldpat.is_shorthand {
3157f602 256 continue;
b039eaaf 257 }
e1599b0c 258 if fieldpat.span.from_expansion() {
83c7162d
XL
259 // Don't lint if this is a macro expansion: macro authors
260 // shouldn't have to worry about this kind of style issue
261 // (Issue #49588)
262 continue;
263 }
dfeec247 264 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
4b012472 265 if cx.tcx.find_field_index(ident, variant)
487cf647 266 == Some(cx.typeck_results().field_index(fieldpat.hir_id))
dfeec247 267 {
c0240ec0 268 cx.emit_span_lint(
2b03887a
FG
269 NON_SHORTHAND_FIELD_PATTERNS,
270 fieldpat.span,
9c376795
FG
271 BuiltinNonShorthandFieldPatterns {
272 ident,
273 suggestion: fieldpat.span,
274 prefix: binding_annot.prefix_str(),
2b03887a
FG
275 },
276 );
c34b1796
AL
277 }
278 }
279 }
280 }
281 }
282}
283
c34b1796 284declare_lint! {
fe692bf9
FG
285 /// The `unsafe_code` lint catches usage of `unsafe` code and other
286 /// potentially unsound constructs like `no_mangle`, `export_name`,
287 /// and `link_section`.
1b1a35ee
XL
288 ///
289 /// ### Example
290 ///
291 /// ```rust,compile_fail
292 /// #![deny(unsafe_code)]
293 /// fn main() {
294 /// unsafe {
295 ///
296 /// }
297 /// }
fe692bf9
FG
298 ///
299 /// #[no_mangle]
300 /// fn func_0() { }
301 ///
302 /// #[export_name = "exported_symbol_name"]
303 /// pub fn name_in_rust() { }
304 ///
305 /// #[no_mangle]
306 /// #[link_section = ".example_section"]
307 /// pub static VAR1: u32 = 1;
1b1a35ee
XL
308 /// ```
309 ///
310 /// {{produces}}
311 ///
312 /// ### Explanation
313 ///
fe692bf9
FG
314 /// This lint is intended to restrict the usage of `unsafe` blocks and other
315 /// constructs (including, but not limited to `no_mangle`, `link_section`
316 /// and `export_name` attributes) wrong usage of which causes undefined
317 /// behavior.
c34b1796
AL
318 UNSAFE_CODE,
319 Allow,
fe692bf9 320 "usage of `unsafe` code and other potentially unsound constructs"
c34b1796
AL
321}
322
532ac7d7 323declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
c34b1796 324
3b2f2976 325impl UnsafeCode {
74b04a01
XL
326 fn report_unsafe(
327 &self,
328 cx: &EarlyContext<'_>,
329 span: Span,
c620b35d 330 decorate: impl for<'a> LintDiagnostic<'a, ()>,
74b04a01 331 ) {
dc9dc135 332 // This comes from a macro that has `#[allow_internal_unsafe]`.
3b2f2976
XL
333 if span.allows_unsafe() {
334 return;
335 }
336
c0240ec0 337 cx.emit_span_lint(UNSAFE_CODE, span, decorate);
923072b8 338 }
3b2f2976
XL
339}
340
0731742a 341impl EarlyLintPass for UnsafeCode {
9fa01778 342 fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
94222f64 343 if attr.has_name(sym::allow_internal_unsafe) {
9c376795 344 self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
0731742a
XL
345 }
346 }
347
9c376795 348 #[inline]
9fa01778 349 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
e74abb32 350 if let ast::ExprKind::Block(ref blk, _) = e.kind {
dc9dc135 351 // Don't warn about generated blocks; that'll just pollute the output.
0731742a 352 if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
9c376795 353 self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock);
c34b1796
AL
354 }
355 }
356 }
357
9fa01778 358 fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
e74abb32 359 match it.kind {
2b03887a 360 ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
9c376795 361 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
2b03887a 362 }
c34b1796 363
2b03887a 364 ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
9c376795 365 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
2b03887a 366 }
c34b1796 367
6a06907d 368 ast::ItemKind::Fn(..) => {
353b0b11 369 if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
9c376795 370 self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
6a06907d 371 }
923072b8 372
353b0b11 373 if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
9c376795 374 self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
6a06907d 375 }
923072b8 376
353b0b11 377 if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
9c376795 378 self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
923072b8 379 }
6a06907d
XL
380 }
381
382 ast::ItemKind::Static(..) => {
353b0b11 383 if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
9c376795 384 self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
6a06907d 385 }
923072b8 386
353b0b11 387 if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
9c376795 388 self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
6a06907d 389 }
923072b8 390
353b0b11 391 if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
9c376795 392 self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
923072b8 393 }
6a06907d
XL
394 }
395
c620b35d
FG
396 ast::ItemKind::GlobalAsm(..) => {
397 self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm);
398 }
399
ba9703b0 400 _ => {}
c34b1796
AL
401 }
402 }
403
94222f64
XL
404 fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
405 if let ast::AssocItemKind::Fn(..) = it.kind {
353b0b11 406 if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
9c376795 407 self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
94222f64 408 }
353b0b11 409 if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
9c376795 410 self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
94222f64
XL
411 }
412 }
413 }
414
74b04a01
XL
415 fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
416 if let FnKind::Fn(
417 ctxt,
418 _,
419 ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
420 _,
04454e1e 421 _,
74b04a01
XL
422 body,
423 ) = fk
424 {
9c376795 425 let decorator = match ctxt {
74b04a01 426 FnCtxt::Foreign => return,
9c376795
FG
427 FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn,
428 FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod,
429 FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod,
74b04a01 430 };
9c376795 431 self.report_unsafe(cx, span, decorator);
c34b1796
AL
432 }
433 }
434}
435
c34b1796 436declare_lint! {
1b1a35ee
XL
437 /// The `missing_docs` lint detects missing documentation for public items.
438 ///
439 /// ### Example
440 ///
441 /// ```rust,compile_fail
442 /// #![deny(missing_docs)]
443 /// pub fn foo() {}
444 /// ```
445 ///
446 /// {{produces}}
447 ///
448 /// ### Explanation
449 ///
450 /// This lint is intended to ensure that a library is well-documented.
451 /// Items without documentation can be difficult for users to understand
452 /// how to use properly.
453 ///
454 /// This lint is "allow" by default because it can be noisy, and not all
455 /// projects may want to enforce everything to be documented.
94b46f34 456 pub MISSING_DOCS,
c34b1796 457 Allow,
8faf50e0 458 "detects missing documentation for public members",
e74abb32 459 report_in_external_macro
c34b1796
AL
460}
461
add651ee 462pub struct MissingDoc;
c34b1796 463
532ac7d7
XL
464impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
465
94222f64 466fn has_doc(attr: &ast::Attribute) -> bool {
dfeec247
XL
467 if attr.is_doc_comment() {
468 return true;
469 }
470
94222f64 471 if !attr.has_name(sym::doc) {
0731742a
XL
472 return false;
473 }
474
cdc7bbd5 475 if attr.value_str().is_some() {
0731742a
XL
476 return true;
477 }
478
479 if let Some(list) = attr.meta_item_list() {
480 for meta in list {
17df50a5 481 if meta.has_name(sym::hidden) {
0731742a
XL
482 return true;
483 }
484 }
485 }
486
487 false
488}
489
c34b1796 490impl MissingDoc {
dfeec247
XL
491 fn check_missing_docs_attrs(
492 &self,
f035d41b 493 cx: &LateContext<'_>,
94222f64 494 def_id: LocalDefId,
ba9703b0 495 article: &'static str,
dfeec247
XL
496 desc: &'static str,
497 ) {
c34b1796
AL
498 // If we're building a test harness, then warning about
499 // documentation is probably not really relevant right now.
500 if cx.sess().opts.test {
501 return;
502 }
503
c34b1796
AL
504 // Only check publicly-visible items, using the result from the privacy pass.
505 // It's an option so the crate root can also use this function (it doesn't
dc9dc135 506 // have a `NodeId`).
94222f64 507 if def_id != CRATE_DEF_ID {
2b03887a 508 if !cx.effective_visibilities.is_exported(def_id) {
c34b1796
AL
509 return;
510 }
511 }
512
4b012472 513 let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id));
94222f64 514 let has_doc = attrs.iter().any(has_doc);
c34b1796 515 if !has_doc {
c0240ec0 516 cx.emit_span_lint(
2b03887a
FG
517 MISSING_DOCS,
518 cx.tcx.def_span(def_id),
9c376795 519 BuiltinMissingDoc { article, desc },
2b03887a 520 );
c34b1796
AL
521 }
522 }
523}
524
f035d41b 525impl<'tcx> LateLintPass<'tcx> for MissingDoc {
c295e0f8 526 fn check_crate(&mut self, cx: &LateContext<'_>) {
064997fb 527 self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
c34b1796
AL
528 }
529
f035d41b 530 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
49aad941
FG
531 // Previously the Impl and Use types have been excluded from missing docs,
532 // so we will continue to exclude them for compatibility.
533 //
534 // The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
535 if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(_) =
536 it.kind
537 {
538 return;
539 }
c34b1796 540
2b03887a 541 let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
2b03887a 542 self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
c34b1796
AL
543 }
544
f035d41b 545 fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
2b03887a 546 let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
c34b1796 547
2b03887a 548 self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);
c34b1796
AL
549 }
550
f035d41b 551 fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
9ffffee4
FG
552 let context = method_context(cx, impl_item.owner_id.def_id);
553
554 match context {
555 // If the method is an impl for a trait, don't doc.
556 MethodLateContext::TraitImpl => return,
557 MethodLateContext::TraitAutoImpl => {}
558 // If the method is an impl for an item with docs_hidden, don't doc.
559 MethodLateContext::PlainImpl => {
560 let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
add651ee 561 let impl_ty = cx.tcx.type_of(parent).instantiate_identity();
9ffffee4
FG
562 let outerdef = match impl_ty.kind() {
563 ty::Adt(def, _) => Some(def.did()),
564 ty::Foreign(def_id) => Some(*def_id),
565 _ => None,
566 };
567 let is_hidden = match outerdef {
568 Some(id) => cx.tcx.is_doc_hidden(id),
569 None => false,
570 };
571 if is_hidden {
572 return;
573 }
3c0e092e
XL
574 }
575 }
576
2b03887a
FG
577 let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
578 self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);
c34b1796
AL
579 }
580
1b1a35ee 581 fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
2b03887a
FG
582 let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());
583 self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);
1b1a35ee
XL
584 }
585
6a06907d 586 fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
54a0048b 587 if !sf.is_positional() {
487cf647 588 self.check_missing_docs_attrs(cx, sf.def_id, "a", "struct field")
c34b1796
AL
589 }
590 }
591
f035d41b 592 fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
487cf647 593 self.check_missing_docs_attrs(cx, v.def_id, "a", "variant");
c34b1796
AL
594 }
595}
596
597declare_lint! {
1b1a35ee 598 /// The `missing_copy_implementations` lint detects potentially-forgotten
49aad941 599 /// implementations of [`Copy`] for public types.
1b1a35ee
XL
600 ///
601 /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
602 ///
603 /// ### Example
604 ///
605 /// ```rust,compile_fail
606 /// #![deny(missing_copy_implementations)]
607 /// pub struct Foo {
608 /// pub field: i32
609 /// }
610 /// # fn main() {}
611 /// ```
612 ///
613 /// {{produces}}
614 ///
615 /// ### Explanation
616 ///
617 /// Historically (before 1.0), types were automatically marked as `Copy`
618 /// if possible. This was changed so that it required an explicit opt-in
619 /// by implementing the `Copy` trait. As part of this change, a lint was
620 /// added to alert if a copyable type was not marked `Copy`.
621 ///
622 /// This lint is "allow" by default because this code isn't bad; it is
623 /// common to write newtypes like this specifically so that a `Copy` type
624 /// is no longer `Copy`. `Copy` types can result in unintended copies of
625 /// large data which can impact performance.
c34b1796
AL
626 pub MISSING_COPY_IMPLEMENTATIONS,
627 Allow,
628 "detects potentially-forgotten implementations of `Copy`"
629}
630
532ac7d7 631declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
c34b1796 632
f035d41b
XL
633impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
634 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
fe692bf9 635 if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
c34b1796
AL
636 return;
637 }
e74abb32 638 let (def, ty) = match item.kind {
4b012472 639 hir::ItemKind::Struct(_, ast_generics) => {
ff7c6d11 640 if !ast_generics.params.is_empty() {
c34b1796
AL
641 return;
642 }
2b03887a 643 let def = cx.tcx.adt_def(item.owner_id);
fe692bf9 644 (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
9e0c209e 645 }
4b012472 646 hir::ItemKind::Union(_, ast_generics) => {
ff7c6d11 647 if !ast_generics.params.is_empty() {
9e0c209e
SL
648 return;
649 }
2b03887a 650 let def = cx.tcx.adt_def(item.owner_id);
fe692bf9 651 (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
c34b1796 652 }
4b012472 653 hir::ItemKind::Enum(_, ast_generics) => {
ff7c6d11 654 if !ast_generics.params.is_empty() {
c34b1796
AL
655 return;
656 }
2b03887a 657 let def = cx.tcx.adt_def(item.owner_id);
fe692bf9 658 (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
c34b1796
AL
659 }
660 _ => return,
661 };
8bb4bdeb 662 if def.has_dtor(cx.tcx) {
c30ab7b3
SL
663 return;
664 }
9c376795
FG
665
666 // If the type contains a raw pointer, it may represent something like a handle,
667 // and recommending Copy might be a bad idea.
668 for field in def.all_fields() {
669 let did = field.did;
add651ee 670 if cx.tcx.type_of(did).instantiate_identity().is_unsafe_ptr() {
9c376795
FG
671 return;
672 }
673 }
0531ce1d 674 let param_env = ty::ParamEnv::empty();
2b03887a 675 if ty.is_copy_modulo_regions(cx.tcx, param_env) {
c34b1796
AL
676 return;
677 }
add651ee
FG
678 if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) {
679 return;
680 }
ed00b5ec
FG
681 if def.is_variant_list_non_exhaustive()
682 || def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive())
683 {
684 return;
685 }
9c376795
FG
686
687 // We shouldn't recommend implementing `Copy` on stateful things,
688 // such as iterators.
689 if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
ed00b5ec
FG
690 && cx
691 .tcx
9c376795
FG
692 .infer_ctxt()
693 .build()
694 .type_implements_trait(iter_trait, [ty], param_env)
695 .must_apply_modulo_regions()
696 {
697 return;
698 }
699
700 // Default value of clippy::trivially_copy_pass_by_ref
701 const MAX_SIZE: u64 = 256;
702
703 if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) {
704 if size > MAX_SIZE {
705 return;
706 }
707 }
708
709 if type_allowed_to_implement_copy(
5e7ed085
FG
710 cx.tcx,
711 param_env,
712 ty,
9ffffee4 713 traits::ObligationCause::misc(item.span, item.owner_id.def_id),
5e7ed085
FG
714 )
715 .is_ok()
716 {
c0240ec0 717 cx.emit_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl);
c34b1796
AL
718 }
719 }
720}
721
add651ee
FG
722/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints.
723fn type_implements_negative_copy_modulo_regions<'tcx>(
724 tcx: TyCtxt<'tcx>,
725 ty: Ty<'tcx>,
726 param_env: ty::ParamEnv<'tcx>,
727) -> bool {
728 let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
e8be2606 729 let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative };
add651ee
FG
730 let obligation = traits::Obligation {
731 cause: traits::ObligationCause::dummy(),
732 param_env,
733 recursion_depth: 0,
734 predicate: ty::Binder::dummy(pred).to_predicate(tcx),
735 };
736
737 tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
738}
739
c34b1796 740declare_lint! {
1b1a35ee 741 /// The `missing_debug_implementations` lint detects missing
49aad941 742 /// implementations of [`fmt::Debug`] for public types.
1b1a35ee
XL
743 ///
744 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
745 ///
746 /// ### Example
747 ///
748 /// ```rust,compile_fail
749 /// #![deny(missing_debug_implementations)]
750 /// pub struct Foo;
751 /// # fn main() {}
752 /// ```
753 ///
754 /// {{produces}}
755 ///
756 /// ### Explanation
757 ///
758 /// Having a `Debug` implementation on all types can assist with
759 /// debugging, as it provides a convenient way to format and display a
760 /// value. Using the `#[derive(Debug)]` attribute will automatically
761 /// generate a typical implementation, or a custom implementation can be
762 /// added by manually implementing the `Debug` trait.
763 ///
764 /// This lint is "allow" by default because adding `Debug` to all types can
765 /// have a negative impact on compile time and code size. It also requires
766 /// boilerplate to be added to every type, which can be an impediment.
c34b1796
AL
767 MISSING_DEBUG_IMPLEMENTATIONS,
768 Allow,
74b04a01 769 "detects missing implementations of Debug"
c34b1796
AL
770}
771
48663c56 772#[derive(Default)]
add651ee 773pub(crate) struct MissingDebugImplementations;
c34b1796 774
532ac7d7
XL
775impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
776
f035d41b
XL
777impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
778 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
fe692bf9 779 if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
c34b1796
AL
780 return;
781 }
782
e74abb32 783 match item.kind {
dfeec247 784 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
c34b1796
AL
785 _ => return,
786 }
787
add651ee
FG
788 // Avoid listing trait impls if the trait is allowed.
789 let (level, _) = cx.tcx.lint_level_at_node(MISSING_DEBUG_IMPLEMENTATIONS, item.hir_id());
790 if level == Level::Allow {
791 return;
c34b1796
AL
792 }
793
add651ee
FG
794 let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return };
795
796 let has_impl = cx
797 .tcx
798 .non_blanket_impls_for_ty(debug, cx.tcx.type_of(item.owner_id).instantiate_identity())
799 .next()
800 .is_some();
801 if !has_impl {
c0240ec0 802 cx.emit_span_lint(
2b03887a
FG
803 MISSING_DEBUG_IMPLEMENTATIONS,
804 item.span,
9c376795 805 BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug },
2b03887a 806 );
c34b1796
AL
807 }
808 }
809}
810
7cac9316 811declare_lint! {
1b1a35ee
XL
812 /// The `anonymous_parameters` lint detects anonymous parameters in trait
813 /// definitions.
814 ///
815 /// ### Example
816 ///
817 /// ```rust,edition2015,compile_fail
818 /// #![deny(anonymous_parameters)]
819 /// // edition 2015
820 /// pub trait Foo {
821 /// fn foo(usize);
822 /// }
823 /// fn main() {}
824 /// ```
825 ///
826 /// {{produces}}
827 ///
828 /// ### Explanation
829 ///
830 /// This syntax is mostly a historical accident, and can be worked around
831 /// quite easily by adding an `_` pattern or a descriptive identifier:
832 ///
833 /// ```rust
834 /// trait Foo {
835 /// fn foo(_: usize);
836 /// }
837 /// ```
838 ///
839 /// This syntax is now a hard error in the 2018 edition. In the 2015
cdc7bbd5 840 /// edition, this lint is "warn" by default. This lint
1b1a35ee
XL
841 /// enables the [`cargo fix`] tool with the `--edition` flag to
842 /// automatically transition old code from the 2015 edition to 2018. The
cdc7bbd5 843 /// tool will run this lint and automatically apply the
1b1a35ee
XL
844 /// suggested fix from the compiler (which is to add `_` to each
845 /// parameter). This provides a completely automated way to update old
846 /// code for a new edition. See [issue #41686] for more details.
847 ///
848 /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
849 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
7cac9316 850 pub ANONYMOUS_PARAMETERS,
cdc7bbd5 851 Warn,
e74abb32
XL
852 "detects anonymous parameters",
853 @future_incompatible = FutureIncompatibleInfo {
136023e0 854 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
781aab86 855 reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
e74abb32 856 };
7cac9316
XL
857}
858
532ac7d7
XL
859declare_lint_pass!(
860 /// Checks for use of anonymous parameters (RFC 1685).
861 AnonymousParameters => [ANONYMOUS_PARAMETERS]
862);
7cac9316
XL
863
864impl EarlyLintPass for AnonymousParameters {
dfeec247 865 fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
5099ac24 866 if cx.sess().edition() != Edition::Edition2015 {
cdc7bbd5
XL
867 // This is a hard error in future editions; avoid linting and erroring
868 return;
869 }
3c0e092e 870 if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
ba9703b0
XL
871 for arg in sig.decl.inputs.iter() {
872 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
5869c6ff 873 if ident.name == kw::Empty {
2b03887a 874 let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
94b46f34 875
2b03887a
FG
876 let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
877 (snip.as_str(), Applicability::MachineApplicable)
878 } else {
879 ("<type>", Applicability::HasPlaceholders)
880 };
c0240ec0 881 cx.emit_span_lint(
2b03887a
FG
882 ANONYMOUS_PARAMETERS,
883 arg.pat.span,
9c376795
FG
884 BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
885 );
7cac9316
XL
886 }
887 }
dfeec247 888 }
7cac9316
XL
889 }
890 }
891}
892
9fa01778 893/// Check for use of attributes which have been deprecated.
c30ab7b3
SL
894#[derive(Clone)]
895pub struct DeprecatedAttr {
896 // This is not free to compute, so we want to keep it around, rather than
897 // compute it for every attribute.
3c0e092e 898 depr_attrs: Vec<&'static BuiltinAttribute>,
c30ab7b3
SL
899}
900
532ac7d7
XL
901impl_lint_pass!(DeprecatedAttr => []);
902
c30ab7b3
SL
903impl DeprecatedAttr {
904 pub fn new() -> DeprecatedAttr {
dfeec247 905 DeprecatedAttr { depr_attrs: deprecated_attributes() }
c30ab7b3
SL
906 }
907}
908
c30ab7b3 909impl EarlyLintPass for DeprecatedAttr {
9fa01778 910 fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
3c0e092e
XL
911 for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
912 if attr.ident().map(|ident| ident.name) == Some(*name) {
dfeec247
XL
913 if let &AttributeGate::Gated(
914 Stability::Deprecated(link, suggestion),
5869c6ff
XL
915 name,
916 reason,
dfeec247 917 _,
3c0e092e 918 ) = gate
dfeec247 919 {
9c376795
FG
920 let suggestion = match suggestion {
921 Some(msg) => {
922 BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
923 }
924 None => {
925 BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
926 }
927 };
c0240ec0 928 cx.emit_span_lint(
2b03887a
FG
929 DEPRECATED,
930 attr.span,
9c376795 931 BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
2b03887a 932 );
c30ab7b3
SL
933 }
934 return;
935 }
936 }
94222f64 937 if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
c0240ec0 938 cx.emit_span_lint(
2b03887a
FG
939 DEPRECATED,
940 attr.span,
9c376795
FG
941 BuiltinDeprecatedAttrUsed {
942 name: pprust::path_to_string(&attr.get_normal_item().path),
943 suggestion: attr.span,
2b03887a
FG
944 },
945 );
e1599b0c 946 }
c30ab7b3
SL
947 }
948}
949
74b04a01 950fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
136023e0
XL
951 use rustc_ast::token::CommentKind;
952
74b04a01 953 let mut attrs = attrs.iter().peekable();
3b2f2976 954
74b04a01
XL
955 // Accumulate a single span for sugared doc comments.
956 let mut sugared_span: Option<Span> = None;
3b2f2976 957
74b04a01 958 while let Some(attr) = attrs.next() {
136023e0
XL
959 let is_doc_comment = attr.is_doc_comment();
960 if is_doc_comment {
74b04a01 961 sugared_span =
29967ef6 962 Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
74b04a01 963 }
3b2f2976 964
49aad941 965 if attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) {
74b04a01
XL
966 continue;
967 }
532ac7d7 968
1b1a35ee 969 let span = sugared_span.take().unwrap_or(attr.span);
532ac7d7 970
94222f64 971 if is_doc_comment || attr.has_name(sym::doc) {
9c376795
FG
972 let sub = match attr.kind {
973 AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
974 BuiltinUnusedDocCommentSub::PlainHelp
975 }
976 AttrKind::DocComment(CommentKind::Block, _) => {
977 BuiltinUnusedDocCommentSub::BlockHelp
978 }
979 };
c0240ec0 980 cx.emit_span_lint(
2b03887a
FG
981 UNUSED_DOC_COMMENTS,
982 span,
9c376795 983 BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub },
2b03887a 984 );
3b2f2976
XL
985 }
986 }
987}
988
989impl EarlyLintPass for UnusedDocComment {
532ac7d7 990 fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
74b04a01 991 let kind = match stmt.kind {
c620b35d 992 ast::StmtKind::Let(..) => "statements",
29967ef6
XL
993 // Disabled pending discussion in #78306
994 ast::StmtKind::Item(..) => return,
532ac7d7 995 // expressions will be reported by `check_expr`.
74b04a01
XL
996 ast::StmtKind::Empty
997 | ast::StmtKind::Semi(_)
998 | ast::StmtKind::Expr(_)
ba9703b0 999 | ast::StmtKind::MacCall(_) => return,
532ac7d7
XL
1000 };
1001
74b04a01 1002 warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
3b2f2976
XL
1003 }
1004
9fa01778 1005 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
4b012472
FG
1006 if let Some(body) = &arm.body {
1007 let arm_span = arm.pat.span.with_hi(body.span.hi());
1008 warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
1009 }
3b2f2976
XL
1010 }
1011
781aab86
FG
1012 fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1013 if let ast::PatKind::Struct(_, _, fields, _) = &pat.kind {
1014 for field in fields {
1015 warn_if_doc(cx, field.span, "pattern fields", &field.attrs);
1016 }
1017 }
1018 }
1019
9fa01778 1020 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
74b04a01 1021 warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
781aab86
FG
1022
1023 if let ExprKind::Struct(s) = &expr.kind {
1024 for field in &s.fields {
1025 warn_if_doc(cx, field.span, "expression fields", &field.attrs);
1026 }
1027 }
3b2f2976 1028 }
a2a8927a
XL
1029
1030 fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
1031 warn_if_doc(cx, param.ident.span, "generic parameters", &param.attrs);
1032 }
5e7ed085
FG
1033
1034 fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
4b012472 1035 warn_if_doc(cx, block.span, "blocks", block.attrs());
5e7ed085
FG
1036 }
1037
1038 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1039 if let ast::ItemKind::ForeignMod(_) = item.kind {
064997fb 1040 warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
5e7ed085
FG
1041 }
1042 }
3b2f2976
XL
1043}
1044
c34b1796 1045declare_lint! {
1b1a35ee
XL
1046 /// The `no_mangle_const_items` lint detects any `const` items with the
1047 /// [`no_mangle` attribute].
1048 ///
1049 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1050 ///
1051 /// ### Example
1052 ///
1053 /// ```rust,compile_fail
1054 /// #[no_mangle]
1055 /// const FOO: i32 = 5;
1056 /// ```
1057 ///
1058 /// {{produces}}
1059 ///
1060 /// ### Explanation
1061 ///
1062 /// Constants do not have their symbols exported, and therefore, this
1063 /// probably means you meant to use a [`static`], not a [`const`].
1064 ///
1065 /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
1066 /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
c34b1796
AL
1067 NO_MANGLE_CONST_ITEMS,
1068 Deny,
1069 "const items will not have their symbols exported"
1070}
1071
9cc50fc6 1072declare_lint! {
1b1a35ee
XL
1073 /// The `no_mangle_generic_items` lint detects generic items that must be
1074 /// mangled.
1075 ///
1076 /// ### Example
1077 ///
1078 /// ```rust
1079 /// #[no_mangle]
1080 /// fn foo<T>(t: T) {
1081 ///
1082 /// }
1083 /// ```
1084 ///
1085 /// {{produces}}
1086 ///
1087 /// ### Explanation
1088 ///
136023e0 1089 /// A function with generics must have its symbol mangled to accommodate
1b1a35ee
XL
1090 /// the generic parameter. The [`no_mangle` attribute] has no effect in
1091 /// this situation, and should be removed.
1092 ///
1093 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
9cc50fc6
SL
1094 NO_MANGLE_GENERIC_ITEMS,
1095 Warn,
1096 "generic items must be mangled"
1097}
1098
532ac7d7 1099declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
c34b1796 1100
f035d41b
XL
1101impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
1102 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
6a06907d 1103 let attrs = cx.tcx.hir().attrs(it.hir_id());
94222f64
XL
1104 let check_no_mangle_on_generic_fn = |no_mangle_attr: &ast::Attribute,
1105 impl_generics: Option<&hir::Generics<'_>>,
1106 generics: &hir::Generics<'_>,
1107 span| {
1108 for param in
1109 generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1110 {
1111 match param.kind {
1112 GenericParamKind::Lifetime { .. } => {}
1113 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
c0240ec0 1114 cx.emit_span_lint(
2b03887a
FG
1115 NO_MANGLE_GENERIC_ITEMS,
1116 span,
9c376795 1117 BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span },
2b03887a 1118 );
94222f64
XL
1119 break;
1120 }
1121 }
1122 }
1123 };
e74abb32 1124 match it.kind {
4b012472 1125 hir::ItemKind::Fn(.., generics, _) => {
353b0b11 1126 if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
94222f64 1127 check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
c34b1796 1128 }
c30ab7b3 1129 }
8faf50e0 1130 hir::ItemKind::Const(..) => {
353b0b11 1131 if attr::contains_name(attrs, sym::no_mangle) {
9c376795
FG
1132 // account for "pub const" (#45562)
1133 let start = cx
1134 .tcx
1135 .sess
1136 .source_map()
1137 .span_to_snippet(it.span)
1138 .map(|snippet| snippet.find("const").unwrap_or(0))
1139 .unwrap_or(0) as u32;
1140 // `const` is 5 chars
1141 let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
1142
c34b1796
AL
1143 // Const items do not refer to a particular location in memory, and therefore
1144 // don't have anything to attach a symbol to
c0240ec0 1145 cx.emit_span_lint(
2b03887a
FG
1146 NO_MANGLE_CONST_ITEMS,
1147 it.span,
9c376795 1148 BuiltinConstNoMangle { suggestion },
2b03887a 1149 );
c34b1796
AL
1150 }
1151 }
04454e1e
FG
1152 hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
1153 for it in *items {
94222f64 1154 if let hir::AssocItemKind::Fn { .. } = it.kind {
353b0b11
FG
1155 if let Some(no_mangle_attr) =
1156 attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
94222f64
XL
1157 {
1158 check_no_mangle_on_generic_fn(
1159 no_mangle_attr,
1160 Some(generics),
2b03887a 1161 cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(),
94222f64
XL
1162 it.span,
1163 );
1164 }
1165 }
1166 }
1167 }
c30ab7b3 1168 _ => {}
c34b1796
AL
1169 }
1170 }
1171}
1172
bd371182 1173declare_lint! {
1b1a35ee
XL
1174 /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1175 /// T` because it is [undefined behavior].
1176 ///
1177 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1178 ///
1179 /// ### Example
1180 ///
1181 /// ```rust,compile_fail
1182 /// unsafe {
1183 /// let y = std::mem::transmute::<&i32, &mut i32>(&5);
1184 /// }
1185 /// ```
1186 ///
1187 /// {{produces}}
1188 ///
1189 /// ### Explanation
1190 ///
1191 /// Certain assumptions are made about aliasing of data, and this transmute
1192 /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1193 ///
1194 /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
bd371182
AL
1195 MUTABLE_TRANSMUTES,
1196 Deny,
5099ac24 1197 "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
bd371182
AL
1198}
1199
532ac7d7 1200declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
bd371182 1201
f035d41b
XL
1202impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1203 fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
487cf647 1204 if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) =
1b1a35ee 1205 get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
ba9703b0 1206 {
487cf647 1207 if from_mutbl < to_mutbl {
c0240ec0 1208 cx.emit_span_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);
bd371182 1209 }
bd371182
AL
1210 }
1211
f035d41b
XL
1212 fn get_transmute_from_to<'tcx>(
1213 cx: &LateContext<'tcx>,
dfeec247
XL
1214 expr: &hir::Expr<'_>,
1215 ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
e74abb32 1216 let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
f035d41b 1217 cx.qpath_res(qpath, expr.hir_id)
476ff2be
SL
1218 } else {
1219 return None;
1220 };
48663c56 1221 if let Res::Def(DefKind::Fn, did) = def {
bd371182
AL
1222 if !def_id_is_transmute(cx, did) {
1223 return None;
1224 }
3dfed10e 1225 let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
041b39d2 1226 let from = sig.inputs().skip_binder()[0];
f035d41b 1227 let to = sig.output().skip_binder();
532ac7d7 1228 return Some((from, to));
bd371182
AL
1229 }
1230 None
1231 }
1232
f035d41b 1233 fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
c620b35d 1234 cx.tcx.is_intrinsic(def_id, sym::transmute)
bd371182
AL
1235 }
1236 }
1237}
1238
c34b1796 1239declare_lint! {
c0240ec0
FG
1240 /// The `unstable_features` lint detects uses of `#![feature]`.
1241 ///
1242 /// ### Example
1243 ///
1244 /// ```rust,compile_fail
1245 /// #![deny(unstable_features)]
1246 /// #![feature(test)]
1247 /// ```
1248 ///
1249 /// {{produces}}
1250 ///
1251 /// ### Explanation
1252 ///
1253 /// In larger nightly-based projects which
1254 ///
1255 /// * consist of a multitude of crates where a subset of crates has to compile on
1256 /// stable either unconditionally or depending on a `cfg` flag to for example
1257 /// allow stable users to depend on them,
1258 /// * don't use nightly for experimental features but for, e.g., unstable options only,
1259 ///
1260 /// this lint may come in handy to enforce policies of these kinds.
c34b1796
AL
1261 UNSTABLE_FEATURES,
1262 Allow,
c0240ec0 1263 "enabling unstable features"
c34b1796
AL
1264}
1265
532ac7d7
XL
1266declare_lint_pass!(
1267 /// Forbids using the `#[feature(...)]` attribute
1268 UnstableFeatures => [UNSTABLE_FEATURES]
1269);
b039eaaf 1270
f035d41b 1271impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
3dfed10e 1272 fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
c0240ec0
FG
1273 if attr.has_name(sym::feature)
1274 && let Some(items) = attr.meta_item_list()
1275 {
1276 for item in items {
1277 cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
62682a34 1278 }
c34b1796
AL
1279 }
1280 }
1281}
bd371182 1282
487cf647
FG
1283declare_lint! {
1284 /// The `ungated_async_fn_track_caller` lint warns when the
add651ee
FG
1285 /// `#[track_caller]` attribute is used on an async function
1286 /// without enabling the corresponding unstable feature flag.
487cf647
FG
1287 ///
1288 /// ### Example
1289 ///
1290 /// ```rust
1291 /// #[track_caller]
1292 /// async fn foo() {}
1293 /// ```
1294 ///
1295 /// {{produces}}
1296 ///
1297 /// ### Explanation
1298 ///
1299 /// The attribute must be used in conjunction with the
add651ee 1300 /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]`
9c376795 1301 /// annotation will function as a no-op.
487cf647 1302 ///
add651ee 1303 /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html
487cf647
FG
1304 UNGATED_ASYNC_FN_TRACK_CALLER,
1305 Warn,
add651ee 1306 "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"
487cf647
FG
1307}
1308
1309declare_lint_pass!(
9ffffee4 1310 /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to
487cf647
FG
1311 /// do anything
1312 UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER]
1313);
1314
1315impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
1316 fn check_fn(
1317 &mut self,
1318 cx: &LateContext<'_>,
1319 fn_kind: HirFnKind<'_>,
1320 _: &'tcx FnDecl<'_>,
1321 _: &'tcx Body<'_>,
1322 span: Span,
9ffffee4 1323 def_id: LocalDefId,
487cf647 1324 ) {
781aab86 1325 if fn_kind.asyncness().is_async()
add651ee 1326 && !cx.tcx.features().async_fn_track_caller
487cf647 1327 // Now, check if the function has the `#[track_caller]` attribute
353b0b11 1328 && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
9ffffee4 1329 {
c0240ec0 1330 cx.emit_span_lint(
ed00b5ec
FG
1331 UNGATED_ASYNC_FN_TRACK_CALLER,
1332 attr.span,
c0240ec0 1333 BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
ed00b5ec 1334 );
9ffffee4 1335 }
487cf647
FG
1336 }
1337}
1338
abe05a73 1339declare_lint! {
e8be2606
FG
1340 /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that
1341 /// means neither directly accessible, nor reexported, nor leaked through things like return
1342 /// types.
1b1a35ee
XL
1343 ///
1344 /// ### Example
1345 ///
1346 /// ```rust,compile_fail
1347 /// #![deny(unreachable_pub)]
1348 /// mod foo {
1349 /// pub mod bar {
1350 ///
1351 /// }
1352 /// }
1353 /// ```
1354 ///
1355 /// {{produces}}
1356 ///
1357 /// ### Explanation
1358 ///
fe692bf9
FG
1359 /// The `pub` keyword both expresses an intent for an item to be publicly available, and also
1360 /// signals to the compiler to make the item publicly accessible. The intent can only be
1361 /// satisfied, however, if all items which contain this item are *also* publicly accessible.
1362 /// Thus, this lint serves to identify situations where the intent does not match the reality.
1363 ///
1364 /// If you wish the item to be accessible elsewhere within the crate, but not outside it, the
1365 /// `pub(crate)` visibility is recommended to be used instead. This more clearly expresses the
1366 /// intent that the item is only visible within its own crate.
1b1a35ee
XL
1367 ///
1368 /// This lint is "allow" by default because it will trigger for a large
1369 /// amount existing Rust code, and has some false-positives. Eventually it
1370 /// is desired for this to become warn-by-default.
0531ce1d 1371 pub UNREACHABLE_PUB,
abe05a73
XL
1372 Allow,
1373 "`pub` items not reachable from crate root"
1374}
1375
532ac7d7
XL
1376declare_lint_pass!(
1377 /// Lint for items marked `pub` that aren't reachable from other crates.
1378 UnreachablePub => [UNREACHABLE_PUB]
1379);
abe05a73
XL
1380
1381impl UnreachablePub {
dfeec247
XL
1382 fn perform_lint(
1383 &self,
f035d41b 1384 cx: &LateContext<'_>,
dfeec247 1385 what: &str,
94222f64 1386 def_id: LocalDefId,
04454e1e 1387 vis_span: Span,
dfeec247
XL
1388 exportable: bool,
1389 ) {
8faf50e0 1390 let mut applicability = Applicability::MachineApplicable;
2b03887a
FG
1391 if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
1392 {
04454e1e
FG
1393 if vis_span.from_expansion() {
1394 applicability = Applicability::MaybeIncorrect;
1395 }
064997fb 1396 let def_span = cx.tcx.def_span(def_id);
c0240ec0 1397 cx.emit_span_lint(
2b03887a
FG
1398 UNREACHABLE_PUB,
1399 def_span,
9c376795
FG
1400 BuiltinUnreachablePub {
1401 what,
1402 suggestion: (vis_span, applicability),
1403 help: exportable.then_some(()),
2b03887a
FG
1404 },
1405 );
abe05a73
XL
1406 }
1407 }
1408}
1409
f035d41b
XL
1410impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
1411 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
04454e1e
FG
1412 // Do not warn for fake `use` statements.
1413 if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
1414 return;
1415 }
2b03887a 1416 self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
abe05a73
XL
1417 }
1418
f035d41b 1419 fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
2b03887a 1420 self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
abe05a73
XL
1421 }
1422
6a06907d 1423 fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
c620b35d 1424 if matches!(cx.tcx.parent_hir_node(field.hir_id), Node::Variant(_)) {
487cf647
FG
1425 return;
1426 }
1427 self.perform_lint(cx, "field", field.def_id, field.vis_span, false);
abe05a73
XL
1428 }
1429
f035d41b 1430 fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
04454e1e 1431 // Only lint inherent impl items.
2b03887a
FG
1432 if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
1433 self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
04454e1e 1434 }
abe05a73
XL
1435 }
1436}
0531ce1d 1437
0531ce1d 1438declare_lint! {
1b1a35ee
XL
1439 /// The `type_alias_bounds` lint detects bounds in type aliases.
1440 ///
1441 /// ### Example
1442 ///
1443 /// ```rust
1444 /// type SendVec<T: Send> = Vec<T>;
1445 /// ```
1446 ///
1447 /// {{produces}}
1448 ///
1449 /// ### Explanation
1450 ///
1451 /// The trait bounds in a type alias are currently ignored, and should not
1452 /// be included to avoid confusion. This was previously allowed
1453 /// unintentionally; this may become a hard error in the future.
0531ce1d
XL
1454 TYPE_ALIAS_BOUNDS,
1455 Warn,
1456 "bounds in type aliases are not enforced"
1457}
1458
532ac7d7
XL
1459declare_lint_pass!(
1460 /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1461 /// They are relevant when using associated types, but otherwise neither checked
1462 /// at definition site nor enforced at use site.
1463 TypeAliasBounds => [TYPE_ALIAS_BOUNDS]
1464);
0531ce1d
XL
1465
1466impl TypeAliasBounds {
9c376795 1467 pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
0531ce1d 1468 match *qpath {
4b012472 1469 hir::QPath::TypeRelative(ty, _) => {
0531ce1d 1470 // If this is a type variable, we found a `T::Assoc`.
e74abb32 1471 match ty.kind {
4b012472 1472 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
29967ef6
XL
1473 matches!(path.res, Res::Def(DefKind::TyParam, _))
1474 }
dfeec247 1475 _ => false,
0531ce1d
XL
1476 }
1477 }
3dfed10e 1478 hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
0531ce1d
XL
1479 }
1480 }
0531ce1d
XL
1481}
1482
f035d41b
XL
1483impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
1484 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
add651ee
FG
1485 let hir::ItemKind::TyAlias(hir_ty, type_alias_generics) = &item.kind else { return };
1486
781aab86
FG
1487 // Bounds of lazy type aliases and TAITs are respected.
1488 if cx.tcx.type_alias_is_lazy(item.owner_id) {
f035d41b
XL
1489 return;
1490 }
add651ee
FG
1491
1492 let ty = cx.tcx.type_of(item.owner_id).skip_binder();
781aab86 1493 if ty.has_inherent_projections() {
add651ee
FG
1494 // Bounds of type aliases that contain opaque types or inherent projections are respected.
1495 // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = Type::Inherent;`.
49aad941
FG
1496 return;
1497 }
add651ee 1498
0531ce1d 1499 // There must not be a where clause
04454e1e
FG
1500 if type_alias_generics.predicates.is_empty() {
1501 return;
0531ce1d 1502 }
04454e1e
FG
1503
1504 let mut where_spans = Vec::new();
1505 let mut inline_spans = Vec::new();
1506 let mut inline_sugg = Vec::new();
1507 for p in type_alias_generics.predicates {
1508 let span = p.span();
1509 if p.in_where_clause() {
1510 where_spans.push(span);
1511 } else {
1512 for b in p.bounds() {
1513 inline_spans.push(b.span());
1514 }
1515 inline_sugg.push((span, String::new()));
0531ce1d
XL
1516 }
1517 }
04454e1e
FG
1518
1519 let mut suggested_changing_assoc_types = false;
1520 if !where_spans.is_empty() {
9c376795
FG
1521 let sub = (!suggested_changing_assoc_types).then(|| {
1522 suggested_changing_assoc_types = true;
add651ee 1523 SuggestChangingAssocTypes { ty: hir_ty }
04454e1e 1524 });
c0240ec0 1525 cx.emit_span_lint(
9c376795
FG
1526 TYPE_ALIAS_BOUNDS,
1527 where_spans,
1528 BuiltinTypeAliasWhereClause {
1529 suggestion: type_alias_generics.where_clause_span,
1530 sub,
1531 },
1532 );
04454e1e
FG
1533 }
1534
1535 if !inline_spans.is_empty() {
9c376795
FG
1536 let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg };
1537 let sub = (!suggested_changing_assoc_types).then(|| {
1538 suggested_changing_assoc_types = true;
add651ee 1539 SuggestChangingAssocTypes { ty: hir_ty }
04454e1e 1540 });
c0240ec0 1541 cx.emit_span_lint(
9c376795
FG
1542 TYPE_ALIAS_BOUNDS,
1543 inline_spans,
1544 BuiltinTypeAliasGenericBounds { suggestion, sub },
1545 );
04454e1e 1546 }
0531ce1d
XL
1547 }
1548}
1549
94b46f34 1550declare_lint! {
1b1a35ee
XL
1551 /// The `trivial_bounds` lint detects trait bounds that don't depend on
1552 /// any type parameters.
1553 ///
1554 /// ### Example
1555 ///
1556 /// ```rust
1557 /// #![feature(trivial_bounds)]
1558 /// pub struct A where i32: Copy;
1559 /// ```
1560 ///
1561 /// {{produces}}
1562 ///
1563 /// ### Explanation
1564 ///
1565 /// Usually you would not write a trait bound that you know is always
1566 /// true, or never true. However, when using macros, the macro may not
1567 /// know whether or not the constraint would hold or not at the time when
1568 /// generating the code. Currently, the compiler does not alert you if the
1569 /// constraint is always true, and generates an error if it is never true.
1570 /// The `trivial_bounds` feature changes this to be a warning in both
1571 /// cases, giving macros more freedom and flexibility to generate code,
1572 /// while still providing a signal when writing non-macro code that
1573 /// something is amiss.
1574 ///
1575 /// See [RFC 2056] for more details. This feature is currently only
1576 /// available on the nightly channel, see [tracking issue #48214].
1577 ///
1578 /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1579 /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
94b46f34
XL
1580 TRIVIAL_BOUNDS,
1581 Warn,
1582 "these bounds don't depend on an type parameters"
1583}
1584
532ac7d7
XL
1585declare_lint_pass!(
1586 /// Lint for trait and lifetime bounds that don't depend on type parameters
1587 /// which either do nothing, or stop the item from being used.
1588 TrivialConstraints => [TRIVIAL_BOUNDS]
1589);
94b46f34 1590
f035d41b
XL
1591impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1592 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
fe692bf9 1593 use rustc_middle::ty::ClauseKind;
94b46f34 1594
94b46f34 1595 if cx.tcx.features().trivial_bounds {
2b03887a 1596 let predicates = cx.tcx.predicates_of(item.owner_id);
e74abb32 1597 for &(predicate, span) in predicates.predicates {
5869c6ff 1598 let predicate_kind_name = match predicate.kind().skip_binder() {
fe692bf9
FG
1599 ClauseKind::Trait(..) => "trait",
1600 ClauseKind::TypeOutlives(..) |
1601 ClauseKind::RegionOutlives(..) => "lifetime",
94b46f34 1602
9ffffee4 1603 // `ConstArgHasType` is never global as `ct` is always a param
fe692bf9 1604 ClauseKind::ConstArgHasType(..)
94b46f34
XL
1605 // Ignore projections, as they can only be global
1606 // if the trait bound is global
fe692bf9 1607 | ClauseKind::Projection(..)
94b46f34 1608 // Ignore bounds that a user can't type
fe692bf9 1609 | ClauseKind::WellFormed(..)
9ffffee4 1610 // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
fe692bf9 1611 | ClauseKind::ConstEvaluatable(..) => continue,
94b46f34 1612 };
5099ac24 1613 if predicate.is_global() {
c0240ec0 1614 cx.emit_span_lint(
2b03887a
FG
1615 TRIVIAL_BOUNDS,
1616 span,
9c376795 1617 BuiltinTrivialBounds { predicate_kind_name, predicate },
2b03887a 1618 );
94b46f34
XL
1619 }
1620 }
1621 }
1622 }
1623}
1624
532ac7d7
XL
1625declare_lint_pass!(
1626 /// Does nothing as a lint pass, but registers some `Lint`s
1627 /// which are used by other parts of the compiler.
1628 SoftLints => [
1629 WHILE_TRUE,
1630 BOX_POINTERS,
1631 NON_SHORTHAND_FIELD_PATTERNS,
1632 UNSAFE_CODE,
1633 MISSING_DOCS,
1634 MISSING_COPY_IMPLEMENTATIONS,
1635 MISSING_DEBUG_IMPLEMENTATIONS,
1636 ANONYMOUS_PARAMETERS,
1637 UNUSED_DOC_COMMENTS,
532ac7d7
XL
1638 NO_MANGLE_CONST_ITEMS,
1639 NO_MANGLE_GENERIC_ITEMS,
1640 MUTABLE_TRANSMUTES,
1641 UNSTABLE_FEATURES,
532ac7d7
XL
1642 UNREACHABLE_PUB,
1643 TYPE_ALIAS_BOUNDS,
1644 TRIVIAL_BOUNDS
1645 ]
1646);
8faf50e0
XL
1647
1648declare_lint! {
1b1a35ee
XL
1649 /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1650 /// pattern], which is deprecated.
1651 ///
1652 /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1653 ///
1654 /// ### Example
1655 ///
c295e0f8 1656 /// ```rust,edition2018
1b1a35ee
XL
1657 /// let x = 123;
1658 /// match x {
1659 /// 0...100 => {}
1660 /// _ => {}
1661 /// }
1662 /// ```
1663 ///
1664 /// {{produces}}
1665 ///
1666 /// ### Explanation
1667 ///
1668 /// The `...` range pattern syntax was changed to `..=` to avoid potential
1669 /// confusion with the [`..` range expression]. Use the new form instead.
1670 ///
1671 /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
8faf50e0 1672 pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
dc9dc135 1673 Warn,
17df50a5
XL
1674 "`...` range patterns are deprecated",
1675 @future_incompatible = FutureIncompatibleInfo {
136023e0 1676 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
781aab86 1677 reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
17df50a5 1678 };
8faf50e0
XL
1679}
1680
48663c56
XL
1681#[derive(Default)]
1682pub struct EllipsisInclusiveRangePatterns {
1683 /// If `Some(_)`, suppress all subsequent pattern
1684 /// warnings for better diagnostics.
1685 node_id: Option<ast::NodeId>,
1686}
1687
1688impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
8faf50e0
XL
1689
1690impl EarlyLintPass for EllipsisInclusiveRangePatterns {
48663c56
XL
1691 fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1692 if self.node_id.is_some() {
1693 // Don't recursively warn about patterns inside range endpoints.
dfeec247 1694 return;
48663c56
XL
1695 }
1696
3dfed10e 1697 use self::ast::{PatKind, RangeSyntax::DotDotDot};
13cf67c4
XL
1698
1699 /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1700 /// corresponding to the ellipsis.
dfeec247 1701 fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
e74abb32 1702 match &pat.kind {
dfeec247
XL
1703 PatKind::Range(
1704 a,
1705 Some(b),
1706 Spanned { span, node: RangeEnd::Included(DotDotDot) },
1707 ) => Some((a.as_deref(), b, *span)),
13cf67c4
XL
1708 _ => None,
1709 }
1710 }
8faf50e0 1711
49aad941 1712 let (parentheses, endpoints) = match &pat.kind {
4b012472 1713 PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(subpat)),
13cf67c4
XL
1714 _ => (false, matches_ellipsis_pat(pat)),
1715 };
1716
1717 if let Some((start, end, join)) = endpoints {
49aad941 1718 if parentheses {
48663c56 1719 self.node_id = Some(pat.id);
4b012472 1720 let end = expr_to_string(end);
17df50a5 1721 let replace = match start {
4b012472 1722 Some(start) => format!("&({}..={})", expr_to_string(start), end),
add651ee 1723 None => format!("&(..={end})"),
17df50a5
XL
1724 };
1725 if join.edition() >= Edition::Edition2021 {
c0240ec0 1726 cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
f2b60f7d
FG
1727 span: pat.span,
1728 suggestion: pat.span,
17df50a5 1729 replace,
f2b60f7d 1730 });
17df50a5 1731 } else {
c0240ec0 1732 cx.emit_span_lint(
9c376795
FG
1733 ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1734 pat.span,
1735 BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise {
1736 suggestion: pat.span,
2b03887a 1737 replace,
9c376795
FG
1738 },
1739 );
17df50a5 1740 }
13cf67c4 1741 } else {
923072b8 1742 let replace = "..=";
17df50a5 1743 if join.edition() >= Edition::Edition2021 {
c0240ec0 1744 cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
f2b60f7d
FG
1745 span: pat.span,
1746 suggestion: join,
1747 replace: replace.to_string(),
1748 });
17df50a5 1749 } else {
c0240ec0 1750 cx.emit_span_lint(
9c376795
FG
1751 ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1752 join,
1753 BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise {
1754 suggestion: join,
1755 },
1756 );
17df50a5 1757 }
13cf67c4 1758 };
8faf50e0
XL
1759 }
1760 }
48663c56
XL
1761
1762 fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1763 if let Some(node_id) = self.node_id {
1764 if pat.id == node_id {
1765 self.node_id = None
1766 }
1767 }
1768 }
8faf50e0
XL
1769}
1770
8faf50e0 1771declare_lint! {
e8be2606 1772 /// The `keyword_idents_2018` lint detects edition keywords being used as an
1b1a35ee
XL
1773 /// identifier.
1774 ///
1775 /// ### Example
1776 ///
1777 /// ```rust,edition2015,compile_fail
e8be2606 1778 /// #![deny(keyword_idents_2018)]
1b1a35ee
XL
1779 /// // edition 2015
1780 /// fn dyn() {}
1781 /// ```
1782 ///
1783 /// {{produces}}
1784 ///
1785 /// ### Explanation
1786 ///
1787 /// Rust [editions] allow the language to evolve without breaking
1788 /// backwards compatibility. This lint catches code that uses new keywords
1789 /// that are added to the language that are used as identifiers (such as a
1790 /// variable name, function name, etc.). If you switch the compiler to a
1791 /// new edition without updating the code, then it will fail to compile if
1792 /// you are using a new keyword as an identifier.
1793 ///
1794 /// You can manually change the identifiers to a non-keyword, or use a
1795 /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1796 ///
1797 /// This lint solves the problem automatically. It is "allow" by default
1798 /// because the code is perfectly valid in older editions. The [`cargo
1799 /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1800 /// and automatically apply the suggested fix from the compiler (which is
1801 /// to use a raw identifier). This provides a completely automated way to
1802 /// update old code for a new edition.
1803 ///
1804 /// [editions]: https://doc.rust-lang.org/edition-guide/
1805 /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1806 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
e8be2606 1807 pub KEYWORD_IDENTS_2018,
8faf50e0 1808 Allow,
e74abb32
XL
1809 "detects edition keywords being used as an identifier",
1810 @future_incompatible = FutureIncompatibleInfo {
136023e0 1811 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
781aab86 1812 reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
e74abb32 1813 };
8faf50e0
XL
1814}
1815
e8be2606
FG
1816declare_lint! {
1817 /// The `keyword_idents_2024` lint detects edition keywords being used as an
1818 /// identifier.
1819 ///
1820 /// ### Example
1821 ///
1822 /// ```rust,edition2015,compile_fail
1823 /// #![deny(keyword_idents_2024)]
1824 /// // edition 2015
1825 /// fn gen() {}
1826 /// ```
1827 ///
1828 /// {{produces}}
1829 ///
1830 /// ### Explanation
1831 ///
1832 /// Rust [editions] allow the language to evolve without breaking
1833 /// backwards compatibility. This lint catches code that uses new keywords
1834 /// that are added to the language that are used as identifiers (such as a
1835 /// variable name, function name, etc.). If you switch the compiler to a
1836 /// new edition without updating the code, then it will fail to compile if
1837 /// you are using a new keyword as an identifier.
1838 ///
1839 /// You can manually change the identifiers to a non-keyword, or use a
1840 /// [raw identifier], for example `r#gen`, to transition to a new edition.
1841 ///
1842 /// This lint solves the problem automatically. It is "allow" by default
1843 /// because the code is perfectly valid in older editions. The [`cargo
1844 /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1845 /// and automatically apply the suggested fix from the compiler (which is
1846 /// to use a raw identifier). This provides a completely automated way to
1847 /// update old code for a new edition.
1848 ///
1849 /// [editions]: https://doc.rust-lang.org/edition-guide/
1850 /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1851 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1852 pub KEYWORD_IDENTS_2024,
1853 Allow,
1854 "detects edition keywords being used as an identifier",
1855 @future_incompatible = FutureIncompatibleInfo {
1856 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
1857 reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1858 };
1859}
1860
532ac7d7
XL
1861declare_lint_pass!(
1862 /// Check for uses of edition keywords used as an identifier.
e8be2606 1863 KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]
532ac7d7 1864);
8faf50e0 1865
532ac7d7 1866struct UnderMacro(bool);
8faf50e0 1867
b7449926 1868impl KeywordIdents {
49aad941
FG
1869 fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
1870 for tt in tokens.trees() {
8faf50e0 1871 match tt {
dc9dc135 1872 // Only report non-raw idents.
064997fb 1873 TokenTree::Token(token, _) => {
c620b35d 1874 if let Some((ident, token::IdentIsRaw::No)) = token.ident() {
dfeec247
XL
1875 self.check_ident_token(cx, UnderMacro(true), ident);
1876 }
8faf50e0 1877 }
4b012472 1878 TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),
8faf50e0
XL
1879 }
1880 }
1881 }
8faf50e0 1882
dfeec247
XL
1883 fn check_ident_token(
1884 &mut self,
1885 cx: &EarlyContext<'_>,
1886 UnderMacro(under_macro): UnderMacro,
f9f354fc 1887 ident: Ident,
dfeec247 1888 ) {
e8be2606
FG
1889 let (lint, edition) = match ident.name {
1890 kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),
1891
1892 // rust-lang/rust#56327: Conservatively do not
1893 // attempt to report occurrences of `dyn` within
1894 // macro definitions or invocations, because `dyn`
1895 // can legitimately occur as a contextual keyword
1896 // in 2015 code denoting its 2018 meaning, and we
1897 // do not want rustfix to inject bugs into working
1898 // code by rewriting such occurrences.
1899 //
1900 // But if we see `dyn` outside of a macro, we know
1901 // its precise role in the parsed AST and thus are
1902 // assured this is truly an attempt to use it as
1903 // an identifier.
1904 kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),
1905
1906 kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),
b7449926 1907
48663c56 1908 _ => return,
b7449926
XL
1909 };
1910
dc9dc135 1911 // Don't lint `r#foo`.
e8be2606
FG
1912 if ident.span.edition() >= edition
1913 || cx.sess().psess.raw_identifier_spans.contains(ident.span)
1914 {
b7449926 1915 return;
8faf50e0 1916 }
b7449926 1917
c0240ec0 1918 cx.emit_span_lint(
e8be2606 1919 lint,
2b03887a 1920 ident.span,
e8be2606 1921 BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span },
2b03887a 1922 );
8faf50e0
XL
1923 }
1924}
0bf4aa26 1925
532ac7d7 1926impl EarlyLintPass for KeywordIdents {
f2b60f7d 1927 fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
49aad941 1928 self.check_tokens(cx, &mac_def.body.tokens);
9fa01778 1929 }
ba9703b0 1930 fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
49aad941 1931 self.check_tokens(cx, &mac.args.tokens);
532ac7d7 1932 }
f9f354fc 1933 fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
532ac7d7 1934 self.check_ident_token(cx, UnderMacro(false), ident);
0bf4aa26
XL
1935 }
1936}
1937
532ac7d7
XL
1938declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
1939
0bf4aa26 1940impl ExplicitOutlivesRequirements {
dc9dc135 1941 fn lifetimes_outliving_lifetime<'tcx>(
487cf647 1942 inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
f2b60f7d 1943 def_id: DefId,
dc9dc135 1944 ) -> Vec<ty::Region<'tcx>> {
dfeec247
XL
1945 inferred_outlives
1946 .iter()
fe692bf9
FG
1947 .filter_map(|(clause, _)| match clause.kind().skip_binder() {
1948 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
4b012472 1949 ty::ReEarlyParam(ebr) if ebr.def_id == def_id => Some(b),
3dfed10e
XL
1950 _ => None,
1951 },
dfeec247
XL
1952 _ => None,
1953 })
1954 .collect()
dc9dc135 1955 }
0bf4aa26 1956
dc9dc135 1957 fn lifetimes_outliving_type<'tcx>(
487cf647 1958 inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
dc9dc135
XL
1959 index: u32,
1960 ) -> Vec<ty::Region<'tcx>> {
dfeec247
XL
1961 inferred_outlives
1962 .iter()
fe692bf9
FG
1963 .filter_map(|(clause, _)| match clause.kind().skip_binder() {
1964 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
3dfed10e 1965 a.is_param(index).then_some(b)
0bf4aa26 1966 }
dfeec247
XL
1967 _ => None,
1968 })
1969 .collect()
dc9dc135
XL
1970 }
1971
dc9dc135
XL
1972 fn collect_outlives_bound_spans<'tcx>(
1973 &self,
1974 tcx: TyCtxt<'tcx>,
dfeec247 1975 bounds: &hir::GenericBounds<'_>,
dc9dc135 1976 inferred_outlives: &[ty::Region<'tcx>],
9c376795 1977 predicate_span: Span,
dc9dc135 1978 ) -> Vec<(usize, Span)> {
9ffffee4 1979 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
dc9dc135
XL
1980
1981 bounds
1982 .iter()
1983 .enumerate()
1984 .filter_map(|(i, bound)| {
9c376795
FG
1985 let hir::GenericBound::Outlives(lifetime) = bound else {
1986 return None;
1987 };
1988
9ffffee4
FG
1989 let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
1990 Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
9c376795 1991 .iter()
4b012472 1992 .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { ebr.def_id == def_id })),
9c376795
FG
1993 _ => false,
1994 };
1995
1996 if !is_inferred {
1997 return None;
dc9dc135 1998 }
9c376795
FG
1999
2000 let span = bound.span().find_ancestor_inside(predicate_span)?;
2001 if in_external_macro(tcx.sess, span) {
2002 return None;
2003 }
2004
2005 Some((i, span))
dc9dc135
XL
2006 })
2007 .collect()
0bf4aa26
XL
2008 }
2009
2010 fn consolidate_outlives_bound_spans(
2011 &self,
2012 lo: Span,
dfeec247
XL
2013 bounds: &hir::GenericBounds<'_>,
2014 bound_spans: Vec<(usize, Span)>,
0bf4aa26
XL
2015 ) -> Vec<Span> {
2016 if bounds.is_empty() {
2017 return Vec::new();
2018 }
2019 if bound_spans.len() == bounds.len() {
dfeec247 2020 let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
0bf4aa26
XL
2021 // If all bounds are inferable, we want to delete the colon, so
2022 // start from just after the parameter (span passed as argument)
2023 vec![lo.to(last_bound_span)]
2024 } else {
2025 let mut merged = Vec::new();
2026 let mut last_merged_i = None;
2027
2028 let mut from_start = true;
2029 for (i, bound_span) in bound_spans {
2030 match last_merged_i {
dc9dc135 2031 // If the first bound is inferable, our span should also eat the leading `+`.
0bf4aa26
XL
2032 None if i == 0 => {
2033 merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
2034 last_merged_i = Some(0);
dfeec247 2035 }
0bf4aa26 2036 // If consecutive bounds are inferable, merge their spans
dfeec247 2037 Some(h) if i == h + 1 => {
0bf4aa26
XL
2038 if let Some(tail) = merged.last_mut() {
2039 // Also eat the trailing `+` if the first
2040 // more-than-one bound is inferable
2041 let to_span = if from_start && i < bounds.len() {
dfeec247 2042 bounds[i + 1].span().shrink_to_lo()
0bf4aa26
XL
2043 } else {
2044 bound_span
2045 };
2046 *tail = tail.to(to_span);
2047 last_merged_i = Some(i);
2048 } else {
2049 bug!("another bound-span visited earlier");
2050 }
dfeec247 2051 }
0bf4aa26
XL
2052 _ => {
2053 // When we find a non-inferable bound, subsequent inferable bounds
2054 // won't be consecutive from the start (and we'll eat the leading
2055 // `+` rather than the trailing one)
2056 from_start = false;
dfeec247 2057 merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
0bf4aa26
XL
2058 last_merged_i = Some(i);
2059 }
2060 }
2061 }
2062 merged
2063 }
2064 }
2065}
2066
f035d41b
XL
2067impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
2068 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
9ffffee4 2069 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
dc9dc135 2070
2b03887a 2071 let def_id = item.owner_id.def_id;
9c376795
FG
2072 if let hir::ItemKind::Struct(_, hir_generics)
2073 | hir::ItemKind::Enum(_, hir_generics)
2074 | hir::ItemKind::Union(_, hir_generics) = item.kind
dc9dc135
XL
2075 {
2076 let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
2077 if inferred_outlives.is_empty() {
2078 return;
2079 }
2080
2081 let ty_generics = cx.tcx.generics_of(def_id);
fe692bf9
FG
2082 let num_where_predicates = hir_generics
2083 .predicates
2084 .iter()
2085 .filter(|predicate| predicate.in_where_clause())
2086 .count();
dc9dc135 2087
0bf4aa26
XL
2088 let mut bound_count = 0;
2089 let mut lint_spans = Vec::new();
0bf4aa26 2090 let mut where_lint_spans = Vec::new();
fe692bf9 2091 let mut dropped_where_predicate_count = 0;
04454e1e 2092 for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
9c376795
FG
2093 let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
2094 match where_predicate {
2095 hir::WherePredicate::RegionPredicate(predicate) => {
9ffffee4
FG
2096 if let Some(ResolvedArg::EarlyBound(region_def_id)) =
2097 cx.tcx.named_bound_var(predicate.lifetime.hir_id)
9c376795 2098 {
a2a8927a 2099 (
9c376795
FG
2100 Self::lifetimes_outliving_lifetime(
2101 inferred_outlives,
2102 region_def_id,
2103 ),
a2a8927a
XL
2104 &predicate.bounds,
2105 predicate.span,
9c376795 2106 predicate.in_where_clause,
a2a8927a 2107 )
9c376795 2108 } else {
dfeec247
XL
2109 continue;
2110 }
dc9dc135 2111 }
9c376795
FG
2112 hir::WherePredicate::BoundPredicate(predicate) => {
2113 // FIXME we can also infer bounds on associated types,
2114 // and should check for them here.
2115 match predicate.bounded_ty.kind {
2116 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
2117 let Res::Def(DefKind::TyParam, def_id) = path.res else {
add651ee
FG
2118 continue;
2119 };
9c376795
FG
2120 let index = ty_generics.param_def_id_to_index[&def_id];
2121 (
2122 Self::lifetimes_outliving_type(inferred_outlives, index),
2123 &predicate.bounds,
2124 predicate.span,
2125 predicate.origin == PredicateOrigin::WhereClause,
2126 )
2127 }
2128 _ => {
2129 continue;
2130 }
2131 }
2132 }
2133 _ => continue,
2134 };
dc9dc135
XL
2135 if relevant_lifetimes.is_empty() {
2136 continue;
2137 }
2138
9c376795
FG
2139 let bound_spans = self.collect_outlives_bound_spans(
2140 cx.tcx,
2141 bounds,
2142 &relevant_lifetimes,
2143 predicate_span,
2144 );
dc9dc135
XL
2145 bound_count += bound_spans.len();
2146
2147 let drop_predicate = bound_spans.len() == bounds.len();
fe692bf9
FG
2148 if drop_predicate && in_where_clause {
2149 dropped_where_predicate_count += 1;
dc9dc135
XL
2150 }
2151
9ffffee4
FG
2152 if drop_predicate {
2153 if !in_where_clause {
2154 lint_spans.push(predicate_span);
2155 } else if predicate_span.from_expansion() {
2156 // Don't try to extend the span if it comes from a macro expansion.
2157 where_lint_spans.push(predicate_span);
fe692bf9 2158 } else if i + 1 < num_where_predicates {
9ffffee4
FG
2159 // If all the bounds on a predicate were inferable and there are
2160 // further predicates, we want to eat the trailing comma.
2161 let next_predicate_span = hir_generics.predicates[i + 1].span();
2162 if next_predicate_span.from_expansion() {
2163 where_lint_spans.push(predicate_span);
2164 } else {
2165 where_lint_spans
2166 .push(predicate_span.to(next_predicate_span.shrink_to_lo()));
2167 }
2168 } else {
2169 // Eat the optional trailing comma after the last predicate.
2170 let where_span = hir_generics.where_clause_span;
2171 if where_span.from_expansion() {
2172 where_lint_spans.push(predicate_span);
2173 } else {
2174 where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi()));
2175 }
2176 }
dc9dc135 2177 } else {
dfeec247 2178 where_lint_spans.extend(self.consolidate_outlives_bound_spans(
9c376795 2179 predicate_span.shrink_to_lo(),
dfeec247
XL
2180 bounds,
2181 bound_spans,
2182 ));
0bf4aa26
XL
2183 }
2184 }
2185
fe692bf9 2186 // If all predicates in where clause are inferable, drop the entire clause
0bf4aa26 2187 // (including the `where`)
fe692bf9
FG
2188 if hir_generics.has_where_clause_predicates
2189 && dropped_where_predicate_count == num_where_predicates
923072b8
FG
2190 {
2191 let where_span = hir_generics.where_clause_span;
dc9dc135
XL
2192 // Extend the where clause back to the closing `>` of the
2193 // generics, except for tuple struct, which have the `where`
2194 // after the fields of the struct.
dfeec247
XL
2195 let full_where_span =
2196 if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
2197 where_span
2198 } else {
2199 hir_generics.span.shrink_to_hi().to(where_span)
2200 };
9c376795
FG
2201
2202 // Due to macro expansions, the `full_where_span` might not actually contain all predicates.
2203 if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) {
2204 lint_spans.push(full_where_span);
2205 } else {
2206 lint_spans.extend(where_lint_spans);
2207 }
0bf4aa26
XL
2208 } else {
2209 lint_spans.extend(where_lint_spans);
2210 }
2211
2212 if !lint_spans.is_empty() {
9c376795
FG
2213 // Do not automatically delete outlives requirements from macros.
2214 let applicability = if lint_spans.iter().all(|sp| sp.can_be_used_for_suggestions())
2215 {
2216 Applicability::MachineApplicable
2217 } else {
2218 Applicability::MaybeIncorrect
2219 };
2220
9ffffee4
FG
2221 // Due to macros, there might be several predicates with the same span
2222 // and we only want to suggest removing them once.
2223 lint_spans.sort_unstable();
2224 lint_spans.dedup();
2225
c0240ec0 2226 cx.emit_span_lint(
2b03887a
FG
2227 EXPLICIT_OUTLIVES_REQUIREMENTS,
2228 lint_spans.clone(),
9c376795
FG
2229 BuiltinExplicitOutlives {
2230 count: bound_count,
2231 suggestion: BuiltinExplicitOutlivesSuggestion {
2232 spans: lint_spans,
2233 applicability,
2234 },
2b03887a
FG
2235 },
2236 );
0bf4aa26 2237 }
0bf4aa26
XL
2238 }
2239 }
0bf4aa26 2240}
416331ca
XL
2241
2242declare_lint! {
1b1a35ee
XL
2243 /// The `incomplete_features` lint detects unstable features enabled with
2244 /// the [`feature` attribute] that may function improperly in some or all
2245 /// cases.
2246 ///
2247 /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2248 ///
2249 /// ### Example
2250 ///
2251 /// ```rust
94222f64 2252 /// #![feature(generic_const_exprs)]
1b1a35ee
XL
2253 /// ```
2254 ///
2255 /// {{produces}}
2256 ///
2257 /// ### Explanation
2258 ///
2259 /// Although it is encouraged for people to experiment with unstable
2260 /// features, some of them are known to be incomplete or faulty. This lint
2261 /// is a signal that the feature has not yet been finished, and you may
2262 /// experience problems with it.
416331ca
XL
2263 pub INCOMPLETE_FEATURES,
2264 Warn,
2265 "incomplete features that may function improperly in some or all cases"
2266}
2267
add651ee
FG
2268declare_lint! {
2269 /// The `internal_features` lint detects unstable features enabled with
2270 /// the [`feature` attribute] that are internal to the compiler or standard
2271 /// library.
2272 ///
2273 /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2274 ///
2275 /// ### Example
2276 ///
2277 /// ```rust
2278 /// #![feature(rustc_attrs)]
2279 /// ```
2280 ///
2281 /// {{produces}}
2282 ///
2283 /// ### Explanation
2284 ///
2285 /// These features are an implementation detail of the compiler and standard
2286 /// library and are not supposed to be used in user code.
2287 pub INTERNAL_FEATURES,
2288 Warn,
2289 "internal features are not supposed to be used"
2290}
2291
416331ca 2292declare_lint_pass!(
ed00b5ec 2293 /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`.
add651ee 2294 IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES]
416331ca
XL
2295);
2296
add651ee 2297impl EarlyLintPass for IncompleteInternalFeatures {
416331ca 2298 fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
add651ee 2299 let features = cx.builder.features();
dfeec247
XL
2300 features
2301 .declared_lang_features
2302 .iter()
2303 .map(|(name, span, _)| (name, span))
416331ca 2304 .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
add651ee 2305 .filter(|(&name, _)| features.incomplete(name) || features.internal(name))
f9f354fc 2306 .for_each(|(&name, &span)| {
add651ee 2307 if features.incomplete(name) {
ed00b5ec
FG
2308 let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
2309 .map(|n| BuiltinFeatureIssueNote { n });
add651ee
FG
2310 let help =
2311 HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
ed00b5ec 2312
c0240ec0 2313 cx.emit_span_lint(
add651ee
FG
2314 INCOMPLETE_FEATURES,
2315 span,
2316 BuiltinIncompleteFeatures { name, note, help },
2317 );
2318 } else {
c0240ec0 2319 cx.emit_span_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name });
add651ee 2320 }
416331ca
XL
2321 });
2322 }
2323}
2324
5869c6ff 2325const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
29967ef6 2326
416331ca 2327declare_lint! {
1b1a35ee 2328 /// The `invalid_value` lint detects creating a value that is not valid,
17df50a5 2329 /// such as a null reference.
1b1a35ee
XL
2330 ///
2331 /// ### Example
2332 ///
2333 /// ```rust,no_run
2334 /// # #![allow(unused)]
2335 /// unsafe {
2336 /// let x: &'static i32 = std::mem::zeroed();
2337 /// }
2338 /// ```
2339 ///
2340 /// {{produces}}
2341 ///
2342 /// ### Explanation
2343 ///
2344 /// In some situations the compiler can detect that the code is creating
2345 /// an invalid value, which should be avoided.
2346 ///
2347 /// In particular, this lint will check for improper use of
2348 /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2349 /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2350 /// lint should provide extra information to indicate what the problem is
2351 /// and a possible solution.
2352 ///
2353 /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2354 /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2355 /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2356 /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2357 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
416331ca
XL
2358 pub INVALID_VALUE,
2359 Warn,
17df50a5 2360 "an invalid value is being created (such as a null reference)"
416331ca
XL
2361}
2362
2363declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
2364
9c376795
FG
2365/// Information about why a type cannot be initialized this way.
2366pub struct InitError {
2367 pub(crate) message: String,
2368 /// Spans from struct fields and similar that can be obtained from just the type.
2369 pub(crate) span: Option<Span>,
2370 /// Used to report a trace through adts.
2371 pub(crate) nested: Option<Box<InitError>>,
2372}
2373impl InitError {
2374 fn spanned(self, span: Span) -> InitError {
2375 Self { span: Some(span), ..self }
2376 }
2377
2378 fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
2379 assert!(self.nested.is_none());
2380 Self { nested: nested.into().map(Box::new), ..self }
2381 }
2382}
2383
2384impl<'a> From<&'a str> for InitError {
2385 fn from(s: &'a str) -> Self {
2386 s.to_owned().into()
2387 }
2388}
2389impl From<String> for InitError {
2390 fn from(message: String) -> Self {
2391 Self { message, span: None, nested: None }
2392 }
2393}
2394
f035d41b
XL
2395impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2396 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
e1599b0c 2397 #[derive(Debug, Copy, Clone, PartialEq)]
dfeec247
XL
2398 enum InitKind {
2399 Zeroed,
2400 Uninit,
fc512014 2401 }
416331ca 2402
e1599b0c 2403 /// Test if this constant is all-0.
dfeec247 2404 fn is_zero(expr: &hir::Expr<'_>) -> bool {
e1599b0c 2405 use hir::ExprKind::*;
3dfed10e 2406 use rustc_ast::LitKind::*;
e74abb32 2407 match &expr.kind {
dfeec247 2408 Lit(lit) => {
e1599b0c
XL
2409 if let Int(i, _) = lit.node {
2410 i == 0
2411 } else {
2412 false
dfeec247
XL
2413 }
2414 }
2415 Tup(tup) => tup.iter().all(is_zero),
2416 _ => false,
e1599b0c
XL
2417 }
2418 }
2419
2420 /// Determine if this expression is a "dangerous initialization".
f035d41b 2421 fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
4b012472 2422 if let hir::ExprKind::Call(path_expr, args) = expr.kind {
60c5eb7d 2423 // Find calls to `mem::{uninitialized,zeroed}` methods.
e74abb32 2424 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
f035d41b 2425 let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
c295e0f8
XL
2426 match cx.tcx.get_diagnostic_name(def_id) {
2427 Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2428 Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2429 Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2430 _ => {}
e1599b0c 2431 }
60c5eb7d 2432 }
f2b60f7d 2433 } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
60c5eb7d 2434 // Find problematic calls to `MaybeUninit::assume_init`.
3dfed10e 2435 let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
60c5eb7d
XL
2436 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
2437 // This is a call to *some* method named `assume_init`.
2438 // See if the `self` parameter is one of the dangerous constructors.
4b012472 2439 if let hir::ExprKind::Call(path_expr, _) = receiver.kind {
60c5eb7d 2440 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
f035d41b 2441 let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
c295e0f8
XL
2442 match cx.tcx.get_diagnostic_name(def_id) {
2443 Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2444 Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2445 _ => {}
60c5eb7d
XL
2446 }
2447 }
2448 }
e1599b0c
XL
2449 }
2450 }
2451
2452 None
2453 }
2454
2b03887a
FG
2455 fn variant_find_init_error<'tcx>(
2456 cx: &LateContext<'tcx>,
487cf647 2457 ty: Ty<'tcx>,
2b03887a 2458 variant: &VariantDef,
add651ee 2459 args: ty::GenericArgsRef<'tcx>,
2b03887a
FG
2460 descr: &str,
2461 init: InitKind,
2462 ) -> Option<InitError> {
487cf647 2463 let mut field_err = variant.fields.iter().find_map(|field| {
add651ee 2464 ty_find_init_error(cx, field.ty(cx.tcx, args), init).map(|mut err| {
487cf647
FG
2465 if !field.did.is_local() {
2466 err
2467 } else if err.span.is_none() {
2468 err.span = Some(cx.tcx.def_span(field.did));
2469 write!(&mut err.message, " (in this {descr})").unwrap();
2470 err
2b03887a 2471 } else {
487cf647
FG
2472 InitError::from(format!("in this {descr}"))
2473 .spanned(cx.tcx.def_span(field.did))
2474 .nested(err)
2b03887a
FG
2475 }
2476 })
487cf647
FG
2477 });
2478
2479 // Check if this ADT has a constrained layout (like `NonNull` and friends).
2480 if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) {
2481 if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &layout.abi {
2482 let range = scalar.valid_range(cx);
2483 let msg = if !range.contains(0) {
2484 "must be non-null"
2485 } else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
2486 // Prefer reporting on the fields over the entire struct for uninit,
2487 // as the information bubbles out and it may be unclear why the type can't
2488 // be null from just its outside signature.
2489
2490 "must be initialized inside its custom valid range"
2491 } else {
2492 return field_err;
2493 };
2494 if let Some(field_err) = &mut field_err {
2495 // Most of the time, if the field error is the same as the struct error,
2496 // the struct error only happens because of the field error.
2497 if field_err.message.contains(msg) {
2498 field_err.message = format!("because {}", field_err.message);
2499 }
2500 }
2501 return Some(InitError::from(format!("`{ty}` {msg}")).nested(field_err));
2502 }
2503 }
2504 field_err
3dfed10e
XL
2505 }
2506
416331ca
XL
2507 /// Return `Some` only if we are sure this type does *not*
2508 /// allow zero initialization.
e1599b0c 2509 fn ty_find_init_error<'tcx>(
5e7ed085 2510 cx: &LateContext<'tcx>,
e1599b0c
XL
2511 ty: Ty<'tcx>,
2512 init: InitKind,
2513 ) -> Option<InitError> {
e8be2606
FG
2514 let ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
2515
ed00b5ec 2516 use rustc_type_ir::TyKind::*;
1b1a35ee 2517 match ty.kind() {
416331ca 2518 // Primitive types that don't like 0 as a value.
487cf647
FG
2519 Ref(..) => Some("references must be non-null".into()),
2520 Adt(..) if ty.is_box() => Some("`Box` must be non-null".into()),
2521 FnPtr(..) => Some("function pointers must be non-null".into()),
2522 Never => Some("the `!` type has no valid value".into()),
e8be2606 2523 RawPtr(ty, _) if matches!(ty.kind(), Dynamic(..)) =>
dfeec247
XL
2524 // raw ptr to dyn Trait
2525 {
487cf647 2526 Some("the vtable of a wide raw pointer must be non-null".into())
dfeec247 2527 }
e1599b0c 2528 // Primitive types with other constraints.
dfeec247 2529 Bool if init == InitKind::Uninit => {
487cf647 2530 Some("booleans must be either `true` or `false`".into())
dfeec247
XL
2531 }
2532 Char if init == InitKind::Uninit => {
487cf647 2533 Some("characters must be a valid Unicode codepoint".into())
dfeec247 2534 }
f2b60f7d 2535 Int(_) | Uint(_) if init == InitKind::Uninit => {
487cf647 2536 Some("integers must be initialized".into())
f2b60f7d 2537 }
487cf647 2538 Float(_) if init == InitKind::Uninit => Some("floats must be initialized".into()),
e8be2606 2539 RawPtr(_, _) if init == InitKind::Uninit => {
487cf647 2540 Some("raw pointers must be initialized".into())
f2b60f7d 2541 }
2b03887a 2542 // Recurse and checks for some compound types. (but not unions)
add651ee 2543 Adt(adt_def, args) if !adt_def.is_union() => {
2b03887a
FG
2544 // Handle structs.
2545 if adt_def.is_struct() {
2546 return variant_find_init_error(
2547 cx,
487cf647 2548 ty,
2b03887a 2549 adt_def.non_enum_variant(),
add651ee 2550 args,
2b03887a
FG
2551 "struct field",
2552 init,
2553 );
2554 }
2555 // And now, enums.
2556 let span = cx.tcx.def_span(adt_def.did());
2557 let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
2558 let definitely_inhabited = match variant
2559 .inhabited_predicate(cx.tcx, *adt_def)
add651ee 2560 .instantiate(cx.tcx, args)
2b03887a
FG
2561 .apply_any_module(cx.tcx, cx.param_env)
2562 {
49aad941 2563 // Entirely skip uninhabited variants.
2b03887a
FG
2564 Some(false) => return None,
2565 // Forward the others, but remember which ones are definitely inhabited.
2566 Some(true) => true,
2567 None => false,
2568 };
2569 Some((variant, definitely_inhabited))
2570 });
2571 let Some(first_variant) = potential_variants.next() else {
add651ee
FG
2572 return Some(
2573 InitError::from("enums with no inhabited variants have no valid value")
2574 .spanned(span),
2575 );
2b03887a
FG
2576 };
2577 // So we have at least one potentially inhabited variant. Might we have two?
2578 let Some(second_variant) = potential_variants.next() else {
2579 // There is only one potentially inhabited variant. So we can recursively check that variant!
2580 return variant_find_init_error(
2581 cx,
487cf647 2582 ty,
4b012472 2583 first_variant.0,
add651ee 2584 args,
2b03887a
FG
2585 "field of the only potentially inhabited enum variant",
2586 init,
2587 );
2588 };
2589 // So we have at least two potentially inhabited variants.
2590 // If we can prove that we have at least two *definitely* inhabited variants,
2591 // then we have a tag and hence leaving this uninit is definitely disallowed.
2592 // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.)
2593 if init == InitKind::Uninit {
2594 let definitely_inhabited = (first_variant.1 as usize)
2595 + (second_variant.1 as usize)
2596 + potential_variants
2597 .filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
2598 .count();
2599 if definitely_inhabited > 1 {
487cf647
FG
2600 return Some(InitError::from(
2601 "enums with multiple inhabited variants have to be initialized to a variant",
2602 ).spanned(span));
3dfed10e 2603 }
416331ca 2604 }
2b03887a
FG
2605 // We couldn't find anything wrong here.
2606 None
416331ca
XL
2607 }
2608 Tuple(..) => {
2609 // Proceed recursively, check all fields.
5e7ed085
FG
2610 ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
2611 }
2612 Array(ty, len) => {
9ffffee4 2613 if matches!(len.try_eval_target_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
5e7ed085
FG
2614 // Array length known at array non-empty -- recurse.
2615 ty_find_init_error(cx, *ty, init)
2616 } else {
2617 // Empty array or size unknown.
2618 None
2619 }
416331ca 2620 }
416331ca
XL
2621 // Conservative fallback.
2622 _ => None,
2623 }
2624 }
2625
e1599b0c
XL
2626 if let Some(init) = is_dangerous_init(cx, expr) {
2627 // This conjures an instance of a type out of nothing,
2628 // using zeroed or uninitialized memory.
2629 // We are extremely conservative with what we warn about.
3dfed10e 2630 let conjured_ty = cx.typeck_results().expr_ty(expr);
9c376795
FG
2631 if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
2632 let msg = match init {
2633 InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
49aad941 2634 InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
9c376795
FG
2635 };
2636 let sub = BuiltinUnpermittedTypeInitSub { err };
c0240ec0 2637 cx.emit_span_lint(
2b03887a
FG
2638 INVALID_VALUE,
2639 expr.span,
9ffffee4
FG
2640 BuiltinUnpermittedTypeInit {
2641 msg,
2642 ty: conjured_ty,
2643 label: expr.span,
2644 sub,
2645 tcx: cx.tcx,
2646 },
2b03887a 2647 );
416331ca
XL
2648 }
2649 }
2650 }
2651}
f035d41b 2652
cdc7bbd5
XL
2653declare_lint! {
2654 /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2655 /// which causes [undefined behavior].
2656 ///
2657 /// ### Example
2658 ///
2659 /// ```rust,no_run
2660 /// # #![allow(unused)]
2661 /// use std::ptr;
2662 /// unsafe {
2663 /// let x = &*ptr::null::<i32>();
2664 /// let x = ptr::addr_of!(*ptr::null::<i32>());
2665 /// let x = *(0 as *const i32);
2666 /// }
2667 /// ```
2668 ///
2669 /// {{produces}}
2670 ///
2671 /// ### Explanation
2672 ///
2673 /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
2674 /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
2675 ///
2676 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2677 pub DEREF_NULLPTR,
2678 Warn,
2679 "detects when an null pointer is dereferenced"
2680}
2681
2682declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
2683
2684impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
2685 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2686 /// test if expression is a null ptr
2687 fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
2688 match &expr.kind {
4b012472 2689 rustc_hir::ExprKind::Cast(expr, ty) => {
cdc7bbd5
XL
2690 if let rustc_hir::TyKind::Ptr(_) = ty.kind {
2691 return is_zero(expr) || is_null_ptr(cx, expr);
2692 }
2693 }
2694 // check for call to `core::ptr::null` or `core::ptr::null_mut`
4b012472 2695 rustc_hir::ExprKind::Call(path, _) => {
cdc7bbd5
XL
2696 if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
2697 if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
c295e0f8
XL
2698 return matches!(
2699 cx.tcx.get_diagnostic_name(def_id),
2700 Some(sym::ptr_null | sym::ptr_null_mut)
2701 );
cdc7bbd5
XL
2702 }
2703 }
2704 }
2705 _ => {}
2706 }
2707 false
2708 }
2709
2710 /// test if expression is the literal `0`
2711 fn is_zero(expr: &hir::Expr<'_>) -> bool {
2712 match &expr.kind {
4b012472 2713 rustc_hir::ExprKind::Lit(lit) => {
cdc7bbd5
XL
2714 if let LitKind::Int(a, _) = lit.node {
2715 return a == 0;
2716 }
2717 }
2718 _ => {}
2719 }
2720 false
2721 }
2722
3c0e092e
XL
2723 if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
2724 if is_null_ptr(cx, expr_deref) {
c0240ec0 2725 cx.emit_span_lint(
2b03887a
FG
2726 DEREF_NULLPTR,
2727 expr.span,
9c376795 2728 BuiltinDerefNullptr { label: expr.span },
2b03887a 2729 );
cdc7bbd5
XL
2730 }
2731 }
2732 }
2733}
94222f64
XL
2734
2735declare_lint! {
2736 /// The `named_asm_labels` lint detects the use of named labels in the
2737 /// inline `asm!` macro.
2738 ///
2739 /// ### Example
2740 ///
2741 /// ```rust,compile_fail
2b03887a 2742 /// # #![feature(asm_experimental_arch)]
a2a8927a
XL
2743 /// use std::arch::asm;
2744 ///
94222f64
XL
2745 /// fn main() {
2746 /// unsafe {
2747 /// asm!("foo: bar");
2748 /// }
2749 /// }
2750 /// ```
2751 ///
2752 /// {{produces}}
2753 ///
2754 /// ### Explanation
2755 ///
2756 /// LLVM is allowed to duplicate inline assembly blocks for any
2757 /// reason, for example when it is in a function that gets inlined. Because
2758 /// of this, GNU assembler [local labels] *must* be used instead of labels
2759 /// with a name. Using named labels might cause assembler or linker errors.
2760 ///
a2a8927a 2761 /// See the explanation in [Rust By Example] for more details.
94222f64
XL
2762 ///
2763 /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
a2a8927a 2764 /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
94222f64
XL
2765 pub NAMED_ASM_LABELS,
2766 Deny,
2767 "named labels in inline assembly",
2768}
2769
2770declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
2771
2772impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
9c376795 2773 #[allow(rustc::diagnostic_outside_of_impl)]
94222f64
XL
2774 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
2775 if let hir::Expr {
c0240ec0 2776 kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }),
94222f64
XL
2777 ..
2778 } = expr
2779 {
c0240ec0
FG
2780 // asm with `options(raw)` does not do replacement with `{` and `}`.
2781 let raw = options.contains(InlineAsmOptions::RAW);
2782
94222f64 2783 for (template_sym, template_snippet, template_span) in template_strs.iter() {
a2a8927a 2784 let template_str = template_sym.as_str();
94222f64
XL
2785 let find_label_span = |needle: &str| -> Option<Span> {
2786 if let Some(template_snippet) = template_snippet {
2787 let snippet = template_snippet.as_str();
2788 if let Some(pos) = snippet.find(needle) {
2789 let end = pos
3c0e092e 2790 + snippet[pos..]
94222f64
XL
2791 .find(|c| c == ':')
2792 .unwrap_or(snippet[pos..].len() - 1);
2793 let inner = InnerSpan::new(pos, end);
2794 return Some(template_span.from_inner(inner));
2795 }
2796 }
2797
2798 None
2799 };
2800
2801 let mut found_labels = Vec::new();
2802
2803 // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
2804 let statements = template_str.split(|c| matches!(c, '\n' | ';'));
2805 for statement in statements {
2806 // If there's a comment, trim it from the statement
2807 let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
c0240ec0
FG
2808
2809 // In this loop, if there is ever a non-label, no labels can come after it.
94222f64 2810 let mut start_idx = 0;
c0240ec0 2811 'label_loop: for (idx, _) in statement.match_indices(':') {
94222f64
XL
2812 let possible_label = statement[start_idx..idx].trim();
2813 let mut chars = possible_label.chars();
c0240ec0
FG
2814
2815 let Some(start) = chars.next() else {
2816 // Empty string means a leading ':' in this section, which is not a label.
2817 break 'label_loop;
a2a8927a 2818 };
c0240ec0
FG
2819
2820 // Whether a { bracket has been seen and its } hasn't been found yet.
2821 let mut in_bracket = false;
2822
2823 // A label starts with an ASCII alphabetic character or . or _
2824 // A label can also start with a format arg, if it's not a raw asm block.
2825 if !raw && start == '{' {
2826 in_bracket = true;
2827 } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) {
2828 break 'label_loop;
2829 }
2830
2831 // Labels continue with ASCII alphanumeric characters, _, or $
2832 for c in chars {
2833 // Inside a template format arg, any character is permitted for the puproses of label detection
2834 // because we assume that it can be replaced with some other valid label string later.
2835 // `options(raw)` asm blocks cannot have format args, so they are excluded from this special case.
2836 if !raw && in_bracket {
2837 if c == '{' {
2838 // Nested brackets are not allowed in format args, this cannot be a label.
2839 break 'label_loop;
2840 }
2841
2842 if c == '}' {
2843 // The end of the format arg.
2844 in_bracket = false;
2845 }
2846 } else if !raw && c == '{' {
2847 // Start of a format arg.
2848 in_bracket = true;
2849 } else {
2850 if !(c.is_ascii_alphanumeric() || matches!(c, '_' | '$')) {
2851 // The potential label had an invalid character inside it, it cannot be a label.
2852 break 'label_loop;
2853 }
2854 }
94222f64
XL
2855 }
2856
c0240ec0
FG
2857 // If all characters passed the label checks, this is likely a label.
2858 found_labels.push(possible_label);
94222f64
XL
2859 start_idx = idx + 1;
2860 }
2861 }
2862
2863 debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
2864
2865 if found_labels.len() > 0 {
2866 let spans = found_labels
2867 .into_iter()
2868 .filter_map(|label| find_label_span(label))
2869 .collect::<Vec<Span>>();
2870 // If there were labels but we couldn't find a span, combine the warnings and use the template span
2871 let target_spans: MultiSpan =
2872 if spans.len() > 0 { spans.into() } else { (*template_span).into() };
2873
c0240ec0 2874 cx.span_lint_with_diagnostics(
94222f64
XL
2875 NAMED_ASM_LABELS,
2876 Some(target_spans),
2b03887a 2877 fluent::lint_builtin_asm_labels,
4b012472 2878 |_| {},
c620b35d 2879 BuiltinLintDiag::NamedAsmLabel(
94222f64
XL
2880 "only local labels of the form `<number>:` should be used in inline asm"
2881 .to_string(),
2882 ),
2883 );
2884 }
2885 }
2886 }
2887 }
2888}
f2b60f7d
FG
2889
2890declare_lint! {
2891 /// The `special_module_name` lint detects module
2892 /// declarations for files that have a special meaning.
2893 ///
2894 /// ### Example
2895 ///
2896 /// ```rust,compile_fail
2897 /// mod lib;
2898 ///
2899 /// fn main() {
2900 /// lib::run();
2901 /// }
2902 /// ```
2903 ///
2904 /// {{produces}}
2905 ///
2906 /// ### Explanation
2907 ///
2908 /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
2909 /// library or binary crate, so declaring them as modules
2910 /// will lead to miscompilation of the crate unless configured
2911 /// explicitly.
2912 ///
2913 /// To access a library from a binary target within the same crate,
2b03887a 2914 /// use `your_crate_name::` as the path instead of `lib::`:
f2b60f7d
FG
2915 ///
2916 /// ```rust,compile_fail
2917 /// // bar/src/lib.rs
2918 /// fn run() {
2919 /// // ...
2920 /// }
2921 ///
2922 /// // bar/src/main.rs
2923 /// fn main() {
2924 /// bar::run();
2925 /// }
2926 /// ```
2927 ///
2928 /// Binary targets cannot be used as libraries and so declaring
2929 /// one as a module is not allowed.
2930 pub SPECIAL_MODULE_NAME,
2931 Warn,
2932 "module declarations for files with a special meaning",
2933}
2934
2935declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
2936
2937impl EarlyLintPass for SpecialModuleName {
2938 fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
2939 for item in &krate.items {
2940 if let ast::ItemKind::Mod(
2941 _,
2942 ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
2943 ) = item.kind
2944 {
2945 if item.attrs.iter().any(|a| a.has_name(sym::path)) {
2946 continue;
2947 }
2948
2949 match item.ident.name.as_str() {
c0240ec0 2950 "lib" => cx.emit_span_lint(
9c376795
FG
2951 SPECIAL_MODULE_NAME,
2952 item.span,
2953 BuiltinSpecialModuleNameUsed::Lib,
2954 ),
c0240ec0 2955 "main" => cx.emit_span_lint(
9c376795
FG
2956 SPECIAL_MODULE_NAME,
2957 item.span,
2958 BuiltinSpecialModuleNameUsed::Main,
2959 ),
2960 _ => continue,
f2b60f7d
FG
2961 }
2962 }
2963 }
2964 }
2965}