@@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
55use  std:: rc:: Rc ; 
66use  std:: str:: { self ,  FromStr } ; 
77
8+ use  crate :: core:: summary:: MissingDependencyError ; 
89use  crate :: AlreadyPrintedError ; 
910use  anyhow:: { anyhow,  bail,  Context  as  _} ; 
1011use  cargo_platform:: Platform ; 
@@ -14,6 +15,7 @@ use cargo_util_schemas::manifest::{RustVersion, StringOrBool};
1415use  itertools:: Itertools ; 
1516use  lazycell:: LazyCell ; 
1617use  pathdiff:: diff_paths; 
18+ use  toml_edit:: ImDocument ; 
1719use  url:: Url ; 
1820
1921use  crate :: core:: compiler:: { CompileKind ,  CompileTarget } ; 
@@ -28,6 +30,7 @@ use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, Worksp
2830use  crate :: sources:: { CRATES_IO_INDEX ,  CRATES_IO_REGISTRY } ; 
2931use  crate :: util:: errors:: { CargoResult ,  ManifestError } ; 
3032use  crate :: util:: interning:: InternedString ; 
33+ use  crate :: util:: lints:: { get_span,  rel_cwd_manifest_path} ; 
3134use  crate :: util:: { self ,  context:: ConfigRelativePath ,  GlobalContext ,  IntoUrl ,  OptVersionReq } ; 
3235
3336mod  embedded; 
@@ -1435,24 +1438,42 @@ fn to_real_manifest(
14351438            . unwrap_or_else ( || semver:: Version :: new ( 0 ,  0 ,  0 ) ) , 
14361439        source_id, 
14371440    ) ; 
1438-     let  summary = Summary :: new ( 
1439-         pkgid, 
1440-         deps, 
1441-         & resolved_toml
1442-             . features 
1443-             . as_ref ( ) 
1444-             . unwrap_or ( & Default :: default ( ) ) 
1445-             . iter ( ) 
1446-             . map ( |( k,  v) | { 
1447-                 ( 
1448-                     InternedString :: new ( k) , 
1449-                     v. iter ( ) . map ( InternedString :: from) . collect ( ) , 
1450-                 ) 
1451-             } ) 
1452-             . collect ( ) , 
1453-         resolved_package. links . as_deref ( ) , 
1454-         rust_version. clone ( ) , 
1455-     ) ?; 
1441+     let  summary = { 
1442+         let  summary = Summary :: new ( 
1443+             pkgid, 
1444+             deps, 
1445+             & resolved_toml
1446+                 . features 
1447+                 . as_ref ( ) 
1448+                 . unwrap_or ( & Default :: default ( ) ) 
1449+                 . iter ( ) 
1450+                 . map ( |( k,  v) | { 
1451+                     ( 
1452+                         InternedString :: new ( k) , 
1453+                         v. iter ( ) . map ( InternedString :: from) . collect ( ) , 
1454+                     ) 
1455+                 } ) 
1456+                 . collect ( ) , 
1457+             resolved_package. links . as_deref ( ) , 
1458+             rust_version. clone ( ) , 
1459+         ) ; 
1460+         // editon2024 stops exposing implicit features, which will strip weak optional dependencies from `dependencies`, 
1461+         // need to check whether `dep_name` is stripped as unused dependency 
1462+         if  let  Err ( ref  err)  = summary { 
1463+             if  let  Some ( missing_dep)  = err. downcast_ref :: < MissingDependencyError > ( )  { 
1464+                 missing_dep_diagnostic ( 
1465+                     missing_dep, 
1466+                     & original_toml, 
1467+                     & document, 
1468+                     & contents, 
1469+                     manifest_file, 
1470+                     gctx, 
1471+                 ) ?; 
1472+             } 
1473+         } 
1474+         summary?
1475+     } ; 
1476+ 
14561477    if  summary. features ( ) . contains_key ( "default-features" )  { 
14571478        warnings. push ( 
14581479            "`default-features = [\" ..\" ]` was found in [features]. \  
@@ -1558,6 +1579,85 @@ fn to_real_manifest(
15581579    Ok ( manifest) 
15591580} 
15601581
1582+ fn  missing_dep_diagnostic ( 
1583+     missing_dep :  & MissingDependencyError , 
1584+     orig_toml :  & TomlManifest , 
1585+     document :  & ImDocument < String > , 
1586+     contents :  & str , 
1587+     manifest_file :  & Path , 
1588+     gctx :  & GlobalContext , 
1589+ )  -> CargoResult < ( ) >  { 
1590+     let  dep_name = missing_dep. dep_name ; 
1591+     let  manifest_path = rel_cwd_manifest_path ( manifest_file,  gctx) ; 
1592+     let  feature_value_span =
1593+         get_span ( & document,  & [ "features" ,  missing_dep. feature . as_str ( ) ] ,  true ) . unwrap ( ) ; 
1594+ 
1595+     let  title = format ! ( 
1596+         "feature `{}` includes `{}`, but `{}` is not a dependency" , 
1597+         missing_dep. feature,  missing_dep. feature_value,  & dep_name
1598+     ) ; 
1599+     let  help = format ! ( "enable the dependency with `dep:{dep_name}`" ) ; 
1600+     let  info_label = format ! ( 
1601+         "`{}` is an unused optional dependency since no feature enables it" , 
1602+         & dep_name
1603+     ) ; 
1604+     let  message = Level :: Error . title ( & title) ; 
1605+     let  snippet = Snippet :: source ( & contents) 
1606+         . origin ( & manifest_path) 
1607+         . fold ( true ) 
1608+         . annotation ( Level :: Error . span ( feature_value_span. start ..feature_value_span. end ) ) ; 
1609+     let  message = if  missing_dep. weak_optional  { 
1610+         let  mut  orig_deps = vec ! [ 
1611+             ( 
1612+                 orig_toml. dependencies. as_ref( ) , 
1613+                 vec![ DepKind :: Normal . kind_table( ) ] , 
1614+             ) , 
1615+             ( 
1616+                 orig_toml. build_dependencies. as_ref( ) , 
1617+                 vec![ DepKind :: Build . kind_table( ) ] , 
1618+             ) , 
1619+         ] ; 
1620+         for  ( name,  platform)  in  orig_toml. target . iter ( ) . flatten ( )  { 
1621+             orig_deps. push ( ( 
1622+                 platform. dependencies . as_ref ( ) , 
1623+                 vec ! [ "target" ,  name,  DepKind :: Normal . kind_table( ) ] , 
1624+             ) ) ; 
1625+             orig_deps. push ( ( 
1626+                 platform. build_dependencies . as_ref ( ) , 
1627+                 vec ! [ "target" ,  name,  DepKind :: Normal . kind_table( ) ] , 
1628+             ) ) ; 
1629+         } 
1630+ 
1631+         if  let  Some ( ( _,  toml_path) )  = orig_deps. iter ( ) . find ( |( deps,  _) | { 
1632+             if  let  Some ( deps)  = deps { 
1633+                 deps. keys ( ) . any ( |p| * p. as_str ( )  == * dep_name) 
1634+             }  else  { 
1635+                 false 
1636+             } 
1637+         } )  { 
1638+             let  toml_path = toml_path
1639+                 . iter ( ) 
1640+                 . map ( |s| * s) 
1641+                 . chain ( std:: iter:: once ( dep_name. as_str ( ) ) ) 
1642+                 . collect :: < Vec < _ > > ( ) ; 
1643+             let  dep_span = get_span ( & document,  & toml_path,  false ) . unwrap ( ) ; 
1644+ 
1645+             message
1646+                 . snippet ( snippet. annotation ( Level :: Warning . span ( dep_span) . label ( & info_label) ) ) 
1647+                 . footer ( Level :: Help . title ( & help) ) 
1648+         }  else  { 
1649+             message. snippet ( snippet) 
1650+         } 
1651+     }  else  { 
1652+         message. snippet ( snippet) 
1653+     } ; 
1654+ 
1655+     if  let  Err ( err)  = gctx. shell ( ) . print_message ( message)  { 
1656+         return  Err ( err. into ( ) ) ; 
1657+     } 
1658+     Err ( AlreadyPrintedError :: new ( anyhow ! ( "" ) . into ( ) ) . into ( ) ) 
1659+ } 
1660+ 
15611661fn  to_virtual_manifest ( 
15621662    contents :  String , 
15631663    document :  toml_edit:: ImDocument < String > , 
0 commit comments