@@ -53,7 +53,11 @@ extern crate clippy_utils;
5353use clippy_utils:: parse_msrv;
5454use rustc_data_structures:: fx:: FxHashSet ;
5555use rustc_lint:: LintId ;
56+ use rustc_semver:: RustcVersion ;
5657use rustc_session:: Session ;
58+ use std:: fs:: File ;
59+ use std:: io:: Read ;
60+ use toml:: Value ;
5761
5862/// Macro used to declare a Clippy lint.
5963///
@@ -443,6 +447,50 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se
443447 store. register_pre_expansion_pass ( move || Box :: new ( attrs:: EarlyAttributes { msrv } ) ) ;
444448}
445449
450+ fn read_msrv ( conf : & Conf , sess : & Session ) -> Option < RustcVersion > {
451+ let clippy_msrv = conf. msrv . as_ref ( ) . and_then ( |s| {
452+ parse_msrv ( s, None , None ) . or_else ( || {
453+ sess. err ( & format ! (
454+ "error reading Clippy's configuration file. `{}` is not a valid Rust version" ,
455+ s
456+ ) ) ;
457+ None
458+ } )
459+ } ) ;
460+
461+ let cargo_msrv = if_chain ! {
462+ if let Ok ( manifest_dir) = std:: env:: var( "CARGO_MANIFEST_DIR" ) ;
463+ if let Ok ( mut file) = File :: open( format!( "{manifest_dir}/Cargo.toml" ) ) ;
464+ let mut cargo_content_str = String :: new( ) ;
465+ if let Ok ( _) = file. read_to_string( & mut cargo_content_str) ;
466+ if let Ok ( cargo_content) = toml:: from_str:: <Value >( & cargo_content_str) ;
467+ if let Some ( package) = cargo_content. get( "package" ) ;
468+ if let Some ( rust_version) = package. get( "rust-version" ) ;
469+ if let Some ( rust_version_str) = rust_version. as_str( ) ;
470+ then {
471+ parse_msrv( rust_version_str, None , None )
472+ } else {
473+ None
474+ }
475+ } ;
476+
477+ if let Some ( cargo_msrv) = cargo_msrv {
478+ if let Some ( clippy_msrv) = clippy_msrv {
479+ // if both files have an msrv, let's compare them and emit a warning if they differ
480+ if clippy_msrv != cargo_msrv {
481+ sess. warn ( & format ! (
482+ "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{}`" ,
483+ clippy_msrv
484+ ) ) ;
485+ return Some ( clippy_msrv) ;
486+ }
487+ }
488+ Some ( cargo_msrv)
489+ } else {
490+ clippy_msrv
491+ }
492+ }
493+
446494#[ doc( hidden) ]
447495pub fn read_conf ( sess : & Session ) -> Conf {
448496 let file_name = match utils:: conf:: lookup_conf_file ( ) {
@@ -458,12 +506,11 @@ pub fn read_conf(sess: &Session) -> Conf {
458506 let TryConf { conf, errors } = utils:: conf:: read ( & file_name) ;
459507 // all conf errors are non-fatal, we just use the default conf in case of error
460508 for error in errors {
461- sess. struct_err ( & format ! (
509+ sess. err ( & format ! (
462510 "error reading Clippy's configuration file `{}`: {}" ,
463511 file_name. display( ) ,
464512 error
465- ) )
466- . emit ( ) ;
513+ ) ) ;
467514 }
468515
469516 conf
@@ -571,16 +618,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
571618 store. register_late_pass ( || Box :: new ( non_octal_unix_permissions:: NonOctalUnixPermissions ) ) ;
572619 store. register_early_pass ( || Box :: new ( unnecessary_self_imports:: UnnecessarySelfImports ) ) ;
573620
574- let msrv = conf. msrv . as_ref ( ) . and_then ( |s| {
575- parse_msrv ( s, None , None ) . or_else ( || {
576- sess. err ( & format ! (
577- "error reading Clippy's configuration file. `{}` is not a valid Rust version" ,
578- s
579- ) ) ;
580- None
581- } )
582- } ) ;
583-
621+ let msrv = read_msrv ( & conf, sess) ;
584622 let avoid_breaking_exported_api = conf. avoid_breaking_exported_api ;
585623 store. register_late_pass ( move || Box :: new ( approx_const:: ApproxConstant :: new ( msrv) ) ) ;
586624 store. register_late_pass ( move || Box :: new ( methods:: Methods :: new ( avoid_breaking_exported_api, msrv) ) ) ;
0 commit comments