@@ -6,6 +6,7 @@ use std::io::prelude::*;
66use std:: path:: { Path , PathBuf } ;
77use std:: process:: Command ;
88
9+ use semver:: Version ;
910use tracing:: * ;
1011
1112use crate :: common:: { Config , Debugger , FailMode , Mode , PassMode } ;
@@ -1113,34 +1114,47 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
11131114 Some ( ( regex, replacement) )
11141115}
11151116
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] ,
1117+ /// Given an llvm version string that looks like `1.2.3-rc1`, extract as semver. Note that this
1118+ /// accepts more than just strict `semver` syntax (as in `major.minor.patch`); this permits omitting
1119+ /// minor and patch version components so users can write e.g. `//@ min-llvm-version: 19` instead of
1120+ /// having to write `//@ min-llvm-version: 19.0.0`.
1121+ ///
1122+ /// Currently panics if the input string is malformed, though we really should not use panic as an
1123+ /// error handling strategy.
1124+ ///
1125+ /// FIXME(jieyouxu): improve error handling
1126+ pub fn extract_llvm_version ( version : & str ) -> Version {
1127+ // The version substring we're interested in usually looks like the `1.2.3`, without any of the
1128+ // fancy suffix like `-rc1` or `meow`.
1129+ let version = version. trim ( ) ;
1130+ let uninterested = |c : char | !c. is_ascii_digit ( ) && c != '.' ;
1131+ let version_without_suffix = match version. split_once ( uninterested) {
1132+ Some ( ( prefix, _suffix) ) => prefix,
11201133 None => version,
11211134 } ;
1122- let components: Vec < u32 > = version_without_suffix
1135+
1136+ let components: Vec < u64 > = version_without_suffix
11231137 . split ( '.' )
1124- . map ( |s| s. parse ( ) . expect ( "Malformed version component" ) )
1138+ . map ( |s| s. parse ( ) . expect ( "llvm version component should consist of only digits " ) )
11251139 . 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 )
1140+
1141+ match & components [ .. ] {
1142+ [ major ] => Version :: new ( * major , 0 , 0 ) ,
1143+ [ major , minor ] => Version :: new ( * major , * minor , 0 ) ,
1144+ [ major , minor , patch ] => Version :: new ( * major , * minor , * patch ) ,
1145+ _ => panic ! ( "malformed llvm version string, expected only 1-3 components: {version}" ) ,
1146+ }
11331147}
11341148
1135- pub fn extract_llvm_version_from_binary ( binary_path : & str ) -> Option < u32 > {
1149+ pub fn extract_llvm_version_from_binary ( binary_path : & str ) -> Option < Version > {
11361150 let output = Command :: new ( binary_path) . arg ( "--version" ) . output ( ) . ok ( ) ?;
11371151 if !output. status . success ( ) {
11381152 return None ;
11391153 }
11401154 let version = String :: from_utf8 ( output. stdout ) . ok ( ) ?;
11411155 for line in version. lines ( ) {
11421156 if let Some ( version) = line. split ( "LLVM version " ) . nth ( 1 ) {
1143- return extract_llvm_version ( version) ;
1157+ return Some ( extract_llvm_version ( version) ) ;
11441158 }
11451159 }
11461160 None
@@ -1247,15 +1261,17 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
12471261 false
12481262}
12491263
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)`.
1264+ /// Takes a directive of the form `"<version1> [- <version2>]"`, returns the numeric representation
1265+ /// of `<version1>` and `<version2>` as tuple: `(<version1>, <version2>)`.
12531266///
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 ) >
1267+ /// If the `<version2>` part is omitted, the second component of the tuple is the same as
1268+ /// `<version1>`.
1269+ fn extract_version_range < ' a , F , VersionTy : Clone > (
1270+ line : & ' a str ,
1271+ parse : F ,
1272+ ) -> Option < ( VersionTy , VersionTy ) >
12571273where
1258- F : Fn ( & str ) -> Option < u32 > ,
1274+ F : Fn ( & ' a str ) -> Option < VersionTy > ,
12591275{
12601276 let mut splits = line. splitn ( 2 , "- " ) . map ( str:: trim) ;
12611277 let min = splits. next ( ) . unwrap ( ) ;
@@ -1273,7 +1289,7 @@ where
12731289 let max = match max {
12741290 Some ( "" ) => return None ,
12751291 Some ( max) => parse ( max) ?,
1276- _ => min,
1292+ _ => min. clone ( ) ,
12771293 } ;
12781294
12791295 Some ( ( min, max) )
@@ -1489,43 +1505,55 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
14891505 } ;
14901506 }
14911507 }
1492- 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
1497- if actual_version < min_version {
1508+ if let Some ( actual_version) = & config. llvm_version {
1509+ // Note that these `min` versions will check for not just major versions.
1510+
1511+ if let Some ( version_string) = config. parse_name_value_directive ( line, "min-llvm-version" ) {
1512+ let min_version = extract_llvm_version ( & version_string) ;
1513+ // Ignore if actual version is smaller than the minimum required version.
1514+ if * actual_version < min_version {
14981515 return IgnoreDecision :: Ignore {
1499- reason : format ! ( "ignored when the LLVM version is older than {rest}" ) ,
1516+ reason : format ! (
1517+ "ignored when the LLVM version {actual_version} is older than {min_version}"
1518+ ) ,
15001519 } ;
15011520 }
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 ( ) ;
1521+ } else if let Some ( version_string) =
1522+ config. parse_name_value_directive ( line, "min-system-llvm-version" )
1523+ {
1524+ let min_version = extract_llvm_version ( & version_string) ;
15041525 // Ignore if using system LLVM and actual version
15051526 // is smaller the minimum required version
1506- if config. system_llvm && actual_version < min_version {
1527+ if config. system_llvm && * actual_version < min_version {
15071528 return IgnoreDecision :: Ignore {
1508- reason : format ! ( "ignored when the system LLVM version is older than {rest}" ) ,
1529+ reason : format ! (
1530+ "ignored when the system LLVM version {actual_version} is older than {min_version}"
1531+ ) ,
15091532 } ;
15101533 }
1511- } else if let Some ( rest) = line. strip_prefix ( "ignore-llvm-version:" ) . map ( str:: trim) {
1534+ } else if let Some ( version_range) =
1535+ config. parse_name_value_directive ( line, "ignore-llvm-version" )
1536+ {
15121537 // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
15131538 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- } ) ;
1539+ extract_version_range ( & version_range, |s| Some ( extract_llvm_version ( s) ) )
1540+ . unwrap_or_else ( || {
1541+ panic ! ( "couldn't parse version range: \" {version_range}\" " ) ;
1542+ } ) ;
15171543 if v_max < v_min {
1518- panic ! ( "Malformed LLVM version range: max < min " )
1544+ panic ! ( "malformed LLVM version range where {v_max} < {v_min} " )
15191545 }
15201546 // Ignore if version lies inside of range.
1521- if actual_version >= v_min && actual_version <= v_max {
1547+ if * actual_version >= v_min && * actual_version <= v_max {
15221548 if v_min == v_max {
15231549 return IgnoreDecision :: Ignore {
1524- reason : format ! ( "ignored when the LLVM version is {rest }" ) ,
1550+ reason : format ! ( "ignored when the LLVM version is {actual_version }" ) ,
15251551 } ;
15261552 } else {
15271553 return IgnoreDecision :: Ignore {
1528- reason : format ! ( "ignored when the LLVM version is between {rest}" ) ,
1554+ reason : format ! (
1555+ "ignored when the LLVM version is between {v_min} and {v_max}"
1556+ ) ,
15291557 } ;
15301558 }
15311559 }
0 commit comments