@@ -8,7 +8,7 @@ use std::process::Command;
8
8
9
9
use tracing:: * ;
10
10
11
- use crate :: common:: { Config , Debugger , FailMode , Mode , PassMode } ;
11
+ use crate :: common:: { Config , Debugger , FailMode , LlvmVersion , Mode , PassMode } ;
12
12
use crate :: debuggers:: { extract_cdb_version, extract_gdb_version} ;
13
13
use crate :: header:: auxiliary:: { AuxProps , parse_and_update_aux} ;
14
14
use crate :: header:: cfg:: { MatchOutcome , parse_cfg_name_directive} ;
@@ -1113,34 +1113,45 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
1113
1113
Some ( ( regex, replacement) )
1114
1114
}
1115
1115
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,
1120
1130
None => version,
1121
1131
} ;
1132
+
1122
1133
let components: Vec < u32 > = version_without_suffix
1123
1134
. split ( '.' )
1124
- . map ( |s| s. parse ( ) . expect ( "Malformed version component" ) )
1135
+ . map ( |s| s. parse ( ) . expect ( "llvm version component should consist of only digits " ) )
1125
1136
. 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
+ }
1133
1144
}
1134
1145
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 > {
1136
1147
let output = Command :: new ( binary_path) . arg ( "--version" ) . output ( ) . ok ( ) ?;
1137
1148
if !output. status . success ( ) {
1138
1149
return None ;
1139
1150
}
1140
1151
let version = String :: from_utf8 ( output. stdout ) . ok ( ) ?;
1141
1152
for line in version. lines ( ) {
1142
1153
if let Some ( version) = line. split ( "LLVM version " ) . nth ( 1 ) {
1143
- return extract_llvm_version ( version) ;
1154
+ return Some ( extract_llvm_version ( version) ) ;
1144
1155
}
1145
1156
}
1146
1157
None
@@ -1247,15 +1258,14 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
1247
1258
false
1248
1259
}
1249
1260
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>)`.
1253
1263
///
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 ) >
1257
1267
where
1258
- F : Fn ( & str ) -> Option < u32 > ,
1268
+ F : Fn ( & str ) -> Option < VersionTy > ,
1259
1269
{
1260
1270
let mut splits = line. splitn ( 2 , "- " ) . map ( str:: trim) ;
1261
1271
let min = splits. next ( ) . unwrap ( ) ;
@@ -1490,42 +1500,54 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
1490
1500
}
1491
1501
}
1492
1502
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.
1497
1508
if actual_version < min_version {
1498
1509
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
+ ) ,
1500
1513
} ;
1501
1514
}
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) ;
1504
1519
// Ignore if using system LLVM and actual version
1505
1520
// is smaller the minimum required version
1506
1521
if config. system_llvm && actual_version < min_version {
1507
1522
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
+ ) ,
1509
1526
} ;
1510
1527
}
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
+ {
1512
1531
// Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
1513
1532
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
+ } ) ;
1517
1537
if v_max < v_min {
1518
- panic ! ( "Malformed LLVM version range: max < min " )
1538
+ panic ! ( "malformed LLVM version range where {v_max} < {v_min} " )
1519
1539
}
1520
1540
// Ignore if version lies inside of range.
1521
1541
if actual_version >= v_min && actual_version <= v_max {
1522
1542
if v_min == v_max {
1523
1543
return IgnoreDecision :: Ignore {
1524
- reason : format ! ( "ignored when the LLVM version is {rest }" ) ,
1544
+ reason : format ! ( "ignored when the LLVM version is {actual_version }" ) ,
1525
1545
} ;
1526
1546
} else {
1527
1547
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
+ ) ,
1529
1551
} ;
1530
1552
}
1531
1553
}
0 commit comments