@@ -6,6 +6,7 @@ use std::io::prelude::*;
6
6
use std:: path:: { Path , PathBuf } ;
7
7
use std:: process:: Command ;
8
8
9
+ use semver:: Version ;
9
10
use tracing:: * ;
10
11
11
12
use crate :: common:: { Config , Debugger , FailMode , Mode , PassMode } ;
@@ -1113,34 +1114,47 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
1113
1114
Some ( ( regex, replacement) )
1114
1115
}
1115
1116
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,
1120
1133
None => version,
1121
1134
} ;
1122
- let components: Vec < u32 > = version_without_suffix
1135
+
1136
+ let components: Vec < u64 > = version_without_suffix
1123
1137
. split ( '.' )
1124
- . map ( |s| s. parse ( ) . expect ( "Malformed version component" ) )
1138
+ . map ( |s| s. parse ( ) . expect ( "llvm version component should consist of only digits " ) )
1125
1139
. 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
+ }
1133
1147
}
1134
1148
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 > {
1136
1150
let output = Command :: new ( binary_path) . arg ( "--version" ) . output ( ) . ok ( ) ?;
1137
1151
if !output. status . success ( ) {
1138
1152
return None ;
1139
1153
}
1140
1154
let version = String :: from_utf8 ( output. stdout ) . ok ( ) ?;
1141
1155
for line in version. lines ( ) {
1142
1156
if let Some ( version) = line. split ( "LLVM version " ) . nth ( 1 ) {
1143
- return extract_llvm_version ( version) ;
1157
+ return Some ( extract_llvm_version ( version) ) ;
1144
1158
}
1145
1159
}
1146
1160
None
@@ -1247,15 +1261,17 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
1247
1261
false
1248
1262
}
1249
1263
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>)`.
1253
1266
///
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 ) >
1257
1273
where
1258
- F : Fn ( & str ) -> Option < u32 > ,
1274
+ F : Fn ( & ' a str ) -> Option < VersionTy > ,
1259
1275
{
1260
1276
let mut splits = line. splitn ( 2 , "- " ) . map ( str:: trim) ;
1261
1277
let min = splits. next ( ) . unwrap ( ) ;
@@ -1273,7 +1289,7 @@ where
1273
1289
let max = match max {
1274
1290
Some ( "" ) => return None ,
1275
1291
Some ( max) => parse ( max) ?,
1276
- _ => min,
1292
+ _ => min. clone ( ) ,
1277
1293
} ;
1278
1294
1279
1295
Some ( ( min, max) )
@@ -1489,43 +1505,55 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
1489
1505
} ;
1490
1506
}
1491
1507
}
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 {
1498
1515
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
+ ) ,
1500
1519
} ;
1501
1520
}
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) ;
1504
1525
// Ignore if using system LLVM and actual version
1505
1526
// is smaller the minimum required version
1506
- if config. system_llvm && actual_version < min_version {
1527
+ if config. system_llvm && * actual_version < min_version {
1507
1528
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
+ ) ,
1509
1532
} ;
1510
1533
}
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
+ {
1512
1537
// Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
1513
1538
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
+ } ) ;
1517
1543
if v_max < v_min {
1518
- panic ! ( "Malformed LLVM version range: max < min " )
1544
+ panic ! ( "malformed LLVM version range where {v_max} < {v_min} " )
1519
1545
}
1520
1546
// 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 {
1522
1548
if v_min == v_max {
1523
1549
return IgnoreDecision :: Ignore {
1524
- reason : format ! ( "ignored when the LLVM version is {rest }" ) ,
1550
+ reason : format ! ( "ignored when the LLVM version is {actual_version }" ) ,
1525
1551
} ;
1526
1552
} else {
1527
1553
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
+ ) ,
1529
1557
} ;
1530
1558
}
1531
1559
}
0 commit comments