11use crate :: core:: dependency:: DepKind ;
22use crate :: core:: FeatureValue :: Dep ;
3- use crate :: core:: { Edition , FeatureValue , Package } ;
3+ use crate :: core:: { Edition , Feature , FeatureValue , Features , Package } ;
44use crate :: util:: interning:: InternedString ;
55use crate :: { CargoResult , GlobalContext } ;
66use annotate_snippets:: { Level , Snippet } ;
@@ -13,10 +13,10 @@ use std::path::Path;
1313use toml_edit:: ImDocument ;
1414
1515fn get_span ( document : & ImDocument < String > , path : & [ & str ] , get_value : bool ) -> Option < Range < usize > > {
16- let mut table = document. as_item ( ) . as_table_like ( ) . unwrap ( ) ;
16+ let mut table = document. as_item ( ) . as_table_like ( ) ? ;
1717 let mut iter = path. into_iter ( ) . peekable ( ) ;
1818 while let Some ( key) = iter. next ( ) {
19- let ( key, item) = table. get_key_value ( key) . unwrap ( ) ;
19+ let ( key, item) = table. get_key_value ( key) ? ;
2020 if iter. peek ( ) . is_none ( ) {
2121 return if get_value {
2222 item. span ( )
@@ -82,6 +82,7 @@ pub struct Lint {
8282 pub groups : & ' static [ LintGroup ] ,
8383 pub default_level : LintLevel ,
8484 pub edition_lint_opts : Option < ( Edition , LintLevel ) > ,
85+ pub feature_gate : Option < & ' static Feature > ,
8586}
8687
8788impl Lint {
@@ -90,7 +91,17 @@ impl Lint {
9091 pkg_lints : & TomlToolLints ,
9192 ws_lints : Option < & TomlToolLints > ,
9293 edition : Edition ,
94+ unstable_features : & Features ,
9395 ) -> ( LintLevel , LintLevelReason ) {
96+ // We should return `Allow` if a lint is behind a feature, but it is
97+ // not enabled, that way the lint does not run.
98+ if self
99+ . feature_gate
100+ . is_some_and ( |f| !unstable_features. is_enabled ( f) )
101+ {
102+ return ( LintLevel :: Allow , LintLevelReason :: Default ) ;
103+ }
104+
94105 self . groups
95106 . iter ( )
96107 . map ( |g| {
@@ -164,7 +175,7 @@ impl From<TomlLintLevel> for LintLevel {
164175 }
165176}
166177
167- #[ derive( Copy , Clone , Debug ) ]
178+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
168179pub enum LintLevelReason {
169180 Default ,
170181 Edition ( Edition ) ,
@@ -228,6 +239,7 @@ const IM_A_TEAPOT: Lint = Lint {
228239 groups : & [ TEST_DUMMY_UNSTABLE ] ,
229240 default_level : LintLevel :: Allow ,
230241 edition_lint_opts : None ,
242+ feature_gate : Some ( Feature :: test_dummy_unstable ( ) ) ,
231243} ;
232244
233245pub fn check_im_a_teapot (
@@ -239,7 +251,13 @@ pub fn check_im_a_teapot(
239251 gctx : & GlobalContext ,
240252) -> CargoResult < ( ) > {
241253 let manifest = pkg. manifest ( ) ;
242- let ( lint_level, reason) = IM_A_TEAPOT . level ( pkg_lints, ws_lints, manifest. edition ( ) ) ;
254+ let ( lint_level, reason) = IM_A_TEAPOT . level (
255+ pkg_lints,
256+ ws_lints,
257+ manifest. edition ( ) ,
258+ manifest. unstable_features ( ) ,
259+ ) ;
260+
243261 if lint_level == LintLevel :: Allow {
244262 return Ok ( ( ) ) ;
245263 }
@@ -295,6 +313,7 @@ const IMPLICIT_FEATURES: Lint = Lint {
295313 groups : & [ ] ,
296314 default_level : LintLevel :: Allow ,
297315 edition_lint_opts : None ,
316+ feature_gate : None ,
298317} ;
299318
300319pub fn check_implicit_features (
@@ -305,19 +324,20 @@ pub fn check_implicit_features(
305324 error_count : & mut usize ,
306325 gctx : & GlobalContext ,
307326) -> CargoResult < ( ) > {
308- let edition = pkg. manifest ( ) . edition ( ) ;
327+ let manifest = pkg. manifest ( ) ;
328+ let edition = manifest. edition ( ) ;
309329 // In Edition 2024+, instead of creating optional features, the dependencies are unused.
310330 // See `UNUSED_OPTIONAL_DEPENDENCY`
311331 if edition >= Edition :: Edition2024 {
312332 return Ok ( ( ) ) ;
313333 }
314334
315- let ( lint_level, reason) = IMPLICIT_FEATURES . level ( pkg_lints, ws_lints, edition) ;
335+ let ( lint_level, reason) =
336+ IMPLICIT_FEATURES . level ( pkg_lints, ws_lints, edition, manifest. unstable_features ( ) ) ;
316337 if lint_level == LintLevel :: Allow {
317338 return Ok ( ( ) ) ;
318339 }
319340
320- let manifest = pkg. manifest ( ) ;
321341 let activated_opt_deps = manifest
322342 . resolved_toml ( )
323343 . features ( )
@@ -373,6 +393,7 @@ const UNUSED_OPTIONAL_DEPENDENCY: Lint = Lint {
373393 groups : & [ ] ,
374394 default_level : LintLevel :: Warn ,
375395 edition_lint_opts : None ,
396+ feature_gate : None ,
376397} ;
377398
378399pub fn unused_dependencies (
@@ -383,18 +404,23 @@ pub fn unused_dependencies(
383404 error_count : & mut usize ,
384405 gctx : & GlobalContext ,
385406) -> CargoResult < ( ) > {
386- let edition = pkg. manifest ( ) . edition ( ) ;
407+ let manifest = pkg. manifest ( ) ;
408+ let edition = manifest. edition ( ) ;
387409 // Unused optional dependencies can only exist on edition 2024+
388410 if edition < Edition :: Edition2024 {
389411 return Ok ( ( ) ) ;
390412 }
391413
392- let ( lint_level, reason) = UNUSED_OPTIONAL_DEPENDENCY . level ( pkg_lints, ws_lints, edition) ;
414+ let ( lint_level, reason) = UNUSED_OPTIONAL_DEPENDENCY . level (
415+ pkg_lints,
416+ ws_lints,
417+ edition,
418+ manifest. unstable_features ( ) ,
419+ ) ;
393420 if lint_level == LintLevel :: Allow {
394421 return Ok ( ( ) ) ;
395422 }
396423 let mut emitted_source = None ;
397- let manifest = pkg. manifest ( ) ;
398424 let original_toml = manifest. original_toml ( ) ;
399425 // Unused dependencies were stripped from the manifest, leaving only the used ones
400426 let used_dependencies = manifest
0 commit comments