@@ -293,201 +293,12 @@ fn explain_lint_level_source(
293293 }
294294}
295295
296- /// The innermost function for emitting lints.
297- ///
298- /// If you are looking to implement a lint, look for higher level functions,
299- /// for example:
300- /// - [`TyCtxt::emit_node_span_lint`]
301- /// - [`TyCtxt::node_lint`]
302- /// - `LintContext::opt_span_lint`
303- ///
304- /// ## `decorate`
305- ///
306- /// It is not intended to call `emit`/`cancel` on the `Diag` passed in the `decorate` callback.
307- #[ track_caller]
308- pub fn lint_level (
309- sess : & Session ,
310- lint : & ' static Lint ,
311- level : LevelAndSource ,
312- span : Option < MultiSpan > ,
313- decorate : impl for <' a , ' b > FnOnce ( & ' b mut Diag < ' a , ( ) > ) ,
314- ) {
315- // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
316- // the "real" work.
317- #[ track_caller]
318- fn lint_level_impl (
319- sess : & Session ,
320- lint : & ' static Lint ,
321- level : LevelAndSource ,
322- span : Option < MultiSpan > ,
323- decorate : Box < dyn ' _ + for <' a , ' b > FnOnce ( & ' b mut Diag < ' a , ( ) > ) > ,
324- ) {
325- let LevelAndSource { level, lint_id, src } = level;
326-
327- // Check for future incompatibility lints and issue a stronger warning.
328- let future_incompatible = lint. future_incompatible ;
329-
330- let has_future_breakage = future_incompatible. map_or (
331- // Default allow lints trigger too often for testing.
332- sess. opts . unstable_opts . future_incompat_test && lint. default_level != Level :: Allow ,
333- |incompat| incompat. report_in_deps ,
334- ) ;
335-
336- // Convert lint level to error level.
337- let err_level = match level {
338- Level :: Allow => {
339- if has_future_breakage {
340- rustc_errors:: Level :: Allow
341- } else {
342- return ;
343- }
344- }
345- Level :: Expect => {
346- // This case is special as we actually allow the lint itself in this context, but
347- // we can't return early like in the case for `Level::Allow` because we still
348- // need the lint diagnostic to be emitted to `rustc_error::DiagCtxtInner`.
349- //
350- // We can also not mark the lint expectation as fulfilled here right away, as it
351- // can still be cancelled in the decorate function. All of this means that we simply
352- // create a `Diag` and continue as we would for warnings.
353- rustc_errors:: Level :: Expect
354- }
355- Level :: ForceWarn => rustc_errors:: Level :: ForceWarning ,
356- Level :: Warn => rustc_errors:: Level :: Warning ,
357- Level :: Deny | Level :: Forbid => rustc_errors:: Level :: Error ,
358- } ;
359- let mut err = Diag :: new ( sess. dcx ( ) , err_level, "" ) ;
360- if let Some ( span) = span {
361- err. span ( span) ;
362- }
363- if let Some ( lint_id) = lint_id {
364- err. lint_id ( lint_id) ;
365- }
366-
367- // If this code originates in a foreign macro, aka something that this crate
368- // did not itself author, then it's likely that there's nothing this crate
369- // can do about it. We probably want to skip the lint entirely.
370- if err. span . primary_spans ( ) . iter ( ) . any ( |s| s. in_external_macro ( sess. source_map ( ) ) ) {
371- // Any suggestions made here are likely to be incorrect, so anything we
372- // emit shouldn't be automatically fixed by rustfix.
373- err. disable_suggestions ( ) ;
374-
375- // If this is a future incompatible that is not an edition fixing lint
376- // it'll become a hard error, so we have to emit *something*. Also,
377- // if this lint occurs in the expansion of a macro from an external crate,
378- // allow individual lints to opt-out from being reported.
379- let incompatible = future_incompatible. is_some_and ( |f| f. reason . edition ( ) . is_none ( ) ) ;
380-
381- // In rustc, for the find_attr macro, we want to always emit this.
382- // This completely circumvents normal lint checking, which usually doesn't happen for macros from other crates.
383- // However, we kind of want that when using find_attr from another rustc crate. So we cheat a little.
384- let is_in_find_attr = sess. enable_internal_lints ( )
385- && err. span . primary_spans ( ) . iter ( ) . any ( |s| {
386- s. source_callee ( ) . is_some_and (
387- |i| matches ! ( i. kind, ExpnKind :: Macro ( _, name) if name. as_str( ) == "find_attr" )
388- )
389- } ) ;
390-
391- if !incompatible && !lint. report_in_external_macro && !is_in_find_attr {
392- err. cancel ( ) ;
393-
394- // Don't continue further, since we don't want to have
395- // `diag_span_note_once` called for a diagnostic that isn't emitted.
396- return ;
397- }
398- }
399-
400- err. is_lint ( lint. name_lower ( ) , has_future_breakage) ;
401-
402- // Lint diagnostics that are covered by the expect level will not be emitted outside
403- // the compiler. It is therefore not necessary to add any information for the user.
404- // This will therefore directly call the decorate function which will in turn emit
405- // the diagnostic.
406- if let Level :: Expect = level {
407- decorate ( & mut err) ;
408- err. emit ( ) ;
409- return ;
410- }
411-
412- if let Some ( future_incompatible) = future_incompatible {
413- let explanation = match future_incompatible. reason {
414- FutureIncompatibilityReason :: FutureReleaseError ( _) => {
415- "this was previously accepted by the compiler but is being phased out; \
416- it will become a hard error in a future release!"
417- . to_owned ( )
418- }
419- FutureIncompatibilityReason :: FutureReleaseSemanticsChange ( _) => {
420- "this will change its meaning in a future release!" . to_owned ( )
421- }
422- FutureIncompatibilityReason :: EditionError ( EditionFcw { edition, .. } ) => {
423- let current_edition = sess. edition ( ) ;
424- format ! (
425- "this is accepted in the current edition (Rust {current_edition}) but is a hard error in Rust {edition}!"
426- )
427- }
428- FutureIncompatibilityReason :: EditionSemanticsChange ( EditionFcw {
429- edition, ..
430- } ) => {
431- format ! ( "this changes meaning in Rust {edition}" )
432- }
433- FutureIncompatibilityReason :: EditionAndFutureReleaseError ( EditionFcw {
434- edition,
435- ..
436- } ) => {
437- format ! (
438- "this was previously accepted by the compiler but is being phased out; \
439- it will become a hard error in Rust {edition} and in a future release in all editions!"
440- )
441- }
442- FutureIncompatibilityReason :: EditionAndFutureReleaseSemanticsChange (
443- EditionFcw { edition, .. } ,
444- ) => {
445- format ! (
446- "this changes meaning in Rust {edition} and in a future release in all editions!"
447- )
448- }
449- FutureIncompatibilityReason :: Custom ( reason, _) => reason. to_owned ( ) ,
450- FutureIncompatibilityReason :: Unreachable => unreachable ! ( ) ,
451- } ;
452-
453- if future_incompatible. explain_reason {
454- err. warn ( explanation) ;
455- }
456-
457- let citation =
458- format ! ( "for more information, see {}" , future_incompatible. reason. reference( ) ) ;
459- err. note ( citation) ;
460- }
461-
462- // Finally, run `decorate`. `decorate` can call `trimmed_path_str` (directly or indirectly),
463- // so we need to make sure when we do call `decorate` that the diagnostic is eventually
464- // emitted or we'll get a `must_produce_diag` ICE.
465- //
466- // When is a diagnostic *eventually* emitted? Well, that is determined by 2 factors:
467- // 1. If the corresponding `rustc_errors::Level` is beyond warning, i.e. `ForceWarning(_)`
468- // or `Error`, then the diagnostic will be emitted regardless of CLI options.
469- // 2. If the corresponding `rustc_errors::Level` is warning, then that can be affected by
470- // `-A warnings` or `--cap-lints=xxx` on the command line. In which case, the diagnostic
471- // will be emitted if `can_emit_warnings` is true.
472- let skip = err_level == rustc_errors:: Level :: Warning && !sess. dcx ( ) . can_emit_warnings ( ) ;
473-
474- if !skip {
475- decorate ( & mut err) ;
476- }
477-
478- explain_lint_level_source ( sess, lint, level, src, & mut err) ;
479- err. emit ( )
480- }
481- lint_level_impl ( sess, lint, level, span, Box :: new ( decorate) )
482- }
483-
484296/// The innermost function for emitting lints implementing the [`trait@Diagnostic`] trait.
485297///
486298/// If you are looking to implement a lint, look for higher level functions,
487299/// for example:
488300///
489301/// - [`TyCtxt::emit_node_span_lint`]
490- /// - [`TyCtxt::node_lint`]
491302/// - `LintContext::opt_span_lint`
492303///
493304/// This function will replace `lint_level` once all its callers have been replaced
0 commit comments