@@ -8,7 +8,7 @@ use std::process::Command;
88
99use tracing:: * ;
1010
11- use crate :: common:: { Config , Debugger , FailMode , Mode , PassMode } ;
11+ use crate :: common:: { Config , Debugger , FailMode , LlvmVersion , Mode , PassMode } ;
1212use crate :: debuggers:: { extract_cdb_version, extract_gdb_version} ;
1313use crate :: header:: auxiliary:: { AuxProps , parse_and_update_aux} ;
1414use crate :: header:: cfg:: { MatchOutcome , parse_cfg_name_directive} ;
@@ -1113,34 +1113,45 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
11131113 Some ( ( regex, replacement) )
11141114}
11151115
1116- pub fn extract_llvm_version ( version : & str ) -> Option < u32 > {
1117- let pat = |c : char | !c. is_ascii_digit ( ) && c != '.' ;
1118- let version_without_suffix = match version. find ( pat) {
1119- Some ( pos) => & version[ ..pos] ,
1116+ /// Given an llvm version string that looks like `1.2.3-rc1`, extract key version info into a
1117+ /// [`LlvmVersion`].
1118+ ///
1119+ /// Currently panics if the input string is malformed, though we really should not use panic as an
1120+ /// error handling strategy.
1121+ ///
1122+ /// FIXME(jieyouxu): improve error handling
1123+ pub fn extract_llvm_version ( version : & str ) -> LlvmVersion {
1124+ // The version substring we're interested in usually looks like the `1.2.3`, without any of the
1125+ // fancy suffix like `-rc1` or `meow`.
1126+ let version = version. trim ( ) ;
1127+ let uninterested = |c : char | !c. is_ascii_digit ( ) && c != '.' ;
1128+ let version_without_suffix = match version. split_once ( uninterested) {
1129+ Some ( ( prefix, _suffix) ) => prefix,
11201130 None => version,
11211131 } ;
1132+
11221133 let components: Vec < u32 > = version_without_suffix
11231134 . split ( '.' )
1124- . map ( |s| s. parse ( ) . expect ( "Malformed version component" ) )
1135+ . map ( |s| s. parse ( ) . expect ( "llvm version component should consist of only digits " ) )
11251136 . collect ( ) ;
1126- let version = match * components {
1127- [ a ] => a * 10_000 ,
1128- [ a , b ] => a * 10_000 + b * 100 ,
1129- [ a , b , c ] => a * 10_000 + b * 100 + c ,
1130- _ => panic ! ( "Malformed version" ) ,
1131- } ;
1132- Some ( version )
1137+
1138+ match & components [ .. ] {
1139+ [ major ] => LlvmVersion :: new ( * major , 0 , 0 ) ,
1140+ [ major , minor ] => LlvmVersion :: new ( * major , * minor , 0 ) ,
1141+ [ major , minor , patch ] => LlvmVersion :: new ( * major , * minor , * patch ) ,
1142+ _ => panic ! ( "malformed llvm version string, expected only 1-3 components: {version}" ) ,
1143+ }
11331144}
11341145
1135- pub fn extract_llvm_version_from_binary ( binary_path : & str ) -> Option < u32 > {
1146+ pub fn extract_llvm_version_from_binary ( binary_path : & str ) -> Option < LlvmVersion > {
11361147 let output = Command :: new ( binary_path) . arg ( "--version" ) . output ( ) . ok ( ) ?;
11371148 if !output. status . success ( ) {
11381149 return None ;
11391150 }
11401151 let version = String :: from_utf8 ( output. stdout ) . ok ( ) ?;
11411152 for line in version. lines ( ) {
11421153 if let Some ( version) = line. split ( "LLVM version " ) . nth ( 1 ) {
1143- return extract_llvm_version ( version) ;
1154+ return Some ( extract_llvm_version ( version) ) ;
11441155 }
11451156 }
11461157 None
@@ -1247,15 +1258,14 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
12471258 false
12481259}
12491260
1250- /// Takes a directive of the form `"<version1> [- <version2>]"`,
1251- /// returns the numeric representation of `<version1>` and `<version2>` as
1252- /// tuple: `(<version1> as u32, <version2> as u32)`.
1261+ /// Takes a directive of the form `"<version1> [- <version2>]"`, returns the numeric representation
1262+ /// of `<version1>` and `<version2>` as tuple: `(<version1>, <version2>)`.
12531263///
1254- /// If the `<version2>` part is omitted, the second component of the tuple
1255- /// is the same as `<version1>`.
1256- fn extract_version_range < F > ( line : & str , parse : F ) -> Option < ( u32 , u32 ) >
1264+ /// If the `<version2>` part is omitted, the second component of the tuple is the same as
1265+ /// `<version1>`.
1266+ fn extract_version_range < F , VersionTy : Copy > ( line : & str , parse : F ) -> Option < ( VersionTy , VersionTy ) >
12571267where
1258- F : Fn ( & str ) -> Option < u32 > ,
1268+ F : Fn ( & str ) -> Option < VersionTy > ,
12591269{
12601270 let mut splits = line. splitn ( 2 , "- " ) . map ( str:: trim) ;
12611271 let min = splits. next ( ) . unwrap ( ) ;
@@ -1490,42 +1500,54 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
14901500 }
14911501 }
14921502 if let Some ( actual_version) = config. llvm_version {
1493- if let Some ( rest) = line. strip_prefix ( "min-llvm-version:" ) . map ( str:: trim) {
1494- let min_version = extract_llvm_version ( rest) . unwrap ( ) ;
1495- // Ignore if actual version is smaller the minimum required
1496- // version
1503+ // Note that these `min` versions will check for not just major versions.
1504+
1505+ if let Some ( version_string) = config. parse_name_value_directive ( line, "min-llvm-version" ) {
1506+ let min_version = extract_llvm_version ( & version_string) ;
1507+ // Ignore if actual version is smaller than the minimum required version.
14971508 if actual_version < min_version {
14981509 return IgnoreDecision :: Ignore {
1499- reason : format ! ( "ignored when the LLVM version is older than {rest}" ) ,
1510+ reason : format ! (
1511+ "ignored when the LLVM version {actual_version} is older than {min_version}"
1512+ ) ,
15001513 } ;
15011514 }
1502- } else if let Some ( rest) = line. strip_prefix ( "min-system-llvm-version:" ) . map ( str:: trim) {
1503- let min_version = extract_llvm_version ( rest) . unwrap ( ) ;
1515+ } else if let Some ( version_string) =
1516+ config. parse_name_value_directive ( line, "min-system-llvm-version" )
1517+ {
1518+ let min_version = extract_llvm_version ( & version_string) ;
15041519 // Ignore if using system LLVM and actual version
15051520 // is smaller the minimum required version
15061521 if config. system_llvm && actual_version < min_version {
15071522 return IgnoreDecision :: Ignore {
1508- reason : format ! ( "ignored when the system LLVM version is older than {rest}" ) ,
1523+ reason : format ! (
1524+ "ignored when the system LLVM version {actual_version} is older than {min_version}"
1525+ ) ,
15091526 } ;
15101527 }
1511- } else if let Some ( rest) = line. strip_prefix ( "ignore-llvm-version:" ) . map ( str:: trim) {
1528+ } else if let Some ( version_range) =
1529+ config. parse_name_value_directive ( line, "ignore-llvm-version" )
1530+ {
15121531 // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
15131532 let ( v_min, v_max) =
1514- extract_version_range ( rest, extract_llvm_version) . unwrap_or_else ( || {
1515- panic ! ( "couldn't parse version range: {:?}" , rest) ;
1516- } ) ;
1533+ extract_version_range ( & version_range, |s| Some ( extract_llvm_version ( s) ) )
1534+ . unwrap_or_else ( || {
1535+ panic ! ( "couldn't parse version range: \" {version_range}\" " ) ;
1536+ } ) ;
15171537 if v_max < v_min {
1518- panic ! ( "Malformed LLVM version range: max < min " )
1538+ panic ! ( "malformed LLVM version range where {v_max} < {v_min} " )
15191539 }
15201540 // Ignore if version lies inside of range.
15211541 if actual_version >= v_min && actual_version <= v_max {
15221542 if v_min == v_max {
15231543 return IgnoreDecision :: Ignore {
1524- reason : format ! ( "ignored when the LLVM version is {rest }" ) ,
1544+ reason : format ! ( "ignored when the LLVM version is {actual_version }" ) ,
15251545 } ;
15261546 } else {
15271547 return IgnoreDecision :: Ignore {
1528- reason : format ! ( "ignored when the LLVM version is between {rest}" ) ,
1548+ reason : format ! (
1549+ "ignored when the LLVM version is between {v_min} and {v_max}"
1550+ ) ,
15291551 } ;
15301552 }
15311553 }
0 commit comments