diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 755f6d1446366..0cb8ac6038357 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -9,6 +9,7 @@ use build_helper::git::GitConfig; use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; +use crate::debuggers::LldbVersion; use crate::edition::Edition; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -597,7 +598,7 @@ pub(crate) struct Config { /// Version of LLDB. /// /// FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! - pub(crate) lldb_version: Option, + pub(crate) lldb_version: Option, /// Version of LLVM. /// diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index 7b57c4c11052b..13e7a5400bfc6 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -1,6 +1,7 @@ use std::process::Command; use camino::Utf8Path; +use semver::Version; pub(crate) fn query_cdb_version(cdb: &Utf8Path) -> Option<[u16; 4]> { let mut version = None; @@ -86,40 +87,89 @@ pub(crate) fn extract_gdb_version(full_version_line: &str) -> Option { Some(((major * 1000) + minor) * 1000 + patch) } +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum LldbVersion { + /// LLDB distributed by Apple as part of Xcode. Uses a unique versioning scheme that does not + /// match LLVM's LLDB. + Apple([u64; 4]), + /// LLDB distributed by LLVM, uses traditional semver. + Llvm(Version), +} + +impl LldbVersion { + /// Takes a string consisting of 1-4 `.`-separated numbers and returns an `LldbVersion::Apple`. + /// + /// If a number fails to parse, that section and any following sections are silently converted + /// to `0` (e.g. `"15.6.asdf.3"` -> `[15, 6, 0, 0]`) + pub(crate) fn apple_from_str(version_num: &str) -> Self { + let mut ver: [u64; 4] = [0; 4]; + + for (i, val) in version_num.split('.').enumerate().take_while(|(i, _)| *i < 4) { + if let Ok(part) = val.parse::() { + ver[i] = part; + } else { + eprintln!( + "Warning: Invalid LLDB version format: '{version_num}'. Falling back to version '{ver:?}'" + ); + break; + } + } + + Self::Apple(ver) + } + + /// Takes a string consisting of 1-3 `.`-separated numbers and returns an `LldbVersion::Llvm`. + /// + /// If a number fails to parse, that section and any following sections are silently converted + /// to `0` (e.g. `"15.asdf.3"` -> `[15, 0, 0]`) + pub(crate) fn llvm_from_str(version_num: &str) -> Self { + let mut ver: [u64; 3] = [0; 3]; + + for (i, val) in version_num.split('.').enumerate().take_while(|(i, _)| *i < 3) { + if let Ok(part) = val.parse::() { + ver[i] = part; + } else { + eprintln!( + "Warning: Invalid LLDB version number format: '{version_num}'. Falling back to version '{ver:?}'" + ); + break; + } + } + + Self::Llvm(Version::new(ver[0], ver[1], ver[2])) + } +} + /// Returns LLDB version -pub(crate) fn extract_lldb_version(full_version_line: &str) -> Option { +pub(crate) fn extract_lldb_version(full_version_line: &str) -> Option { // Extract the major LLDB version from the given version string. // LLDB version strings are different for Apple and non-Apple platforms. // The Apple variant looks like this: // // LLDB-179.5 (older versions) // lldb-300.2.51 (new versions) + // lldb-1703.0.236.21 (even newer versions) // - // We are only interested in the major version number, so this function - // will return `Some(179)` and `Some(300)` respectively. - // - // Upstream versions look like: + // LLVM versions look like: // lldb version 6.0.1 // // There doesn't seem to be a way to correlate the Apple version - // with the upstream version, and since the tests were originally - // written against Apple versions, we make a fake Apple version by - // multiplying the first number by 100. This is a hack. + // with the upstream version. let full_version_line = full_version_line.trim(); - if let Some(apple_ver) = + if let Some(apple_str) = full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) { - if let Some(idx) = apple_ver.find(not_a_digit) { - let version: u32 = apple_ver[..idx].parse().unwrap(); - return Some(version); - } - } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { - if let Some(idx) = lldb_ver.find(not_a_digit) { - let version: u32 = lldb_ver[..idx].parse().ok()?; - return Some(version * 100); - } + let version_str = apple_str.split_whitespace().next()?; + + return Some(LldbVersion::apple_from_str(version_str)); + } + + if let Some(lldb_str) = full_version_line.strip_prefix("lldb version ") { + let version_str = lldb_str.split_whitespace().next()?; + + return Some(LldbVersion::llvm_from_str(version_str)); } None } diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index bb4a595a568c5..a6ee7e27a7232 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -8,7 +8,7 @@ use semver::Version; use tracing::*; use crate::common::{Config, Debugger, PassFailMode, TestMode}; -use crate::debuggers::{extract_cdb_version, extract_gdb_version}; +use crate::debuggers::{LldbVersion, extract_cdb_version, extract_gdb_version}; use crate::directives::auxiliary::parse_and_update_aux; pub(crate) use crate::directives::auxiliary::{AuxCrate, AuxProps}; use crate::directives::directive_names::{ @@ -1101,21 +1101,46 @@ fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { return IgnoreDecision::Continue; } - if let Some(actual_version) = config.lldb_version { - if line.name == "min-lldb-version" - && let Some(rest) = line.value_after_colon().map(str::trim) - { - let min_version = rest.parse().unwrap_or_else(|e| { - panic!("Unexpected format of LLDB version string: {}\n{:?}", rest, e); - }); - // Ignore if actual version is smaller the minimum required - // version - if actual_version < min_version { - return IgnoreDecision::Ignore { - reason: format!("ignored when the LLDB version is {rest}"), + if let Some(actual_version) = &config.lldb_version { + match (line.name, actual_version) { + ("min-apple-lldb-version", LldbVersion::Apple(vers)) => { + let Some(rest) = line.value_after_colon().map(str::trim) else { + return IgnoreDecision::Continue; + }; + + let LldbVersion::Apple(min_vers) = LldbVersion::apple_from_str(rest) else { + unreachable!() }; + + if vers < &min_vers { + return IgnoreDecision::Ignore { + reason: format!( + "ignored when the Apple LLDB version is {}.{}.{}.{}", + vers[0], vers[1], vers[2], vers[3] + ), + }; + } } - } + ("min-llvm-lldb-version", LldbVersion::Llvm(vers)) => { + let Some(rest) = line.value_after_colon().map(str::trim) else { + return IgnoreDecision::Continue; + }; + + let LldbVersion::Llvm(min_vers) = LldbVersion::llvm_from_str(rest) else { + unreachable!() + }; + + if vers < &min_vers { + return IgnoreDecision::Ignore { + reason: format!( + "ignored when the LLDB version is {}.{}.{}", + vers.major, vers.minor, vers.patch + ), + }; + } + } + _ => {} + }; } IgnoreDecision::Continue } diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 058047cd07548..aa942ca48fe02 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -156,9 +156,10 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "lldb-command", "llvm-cov-flags", "max-llvm-major-version", + "min-apple-lldb-version", "min-cdb-version", "min-gdb-version", - "min-lldb-version", + "min-llvm-lldb-version", "min-llvm-version", "min-system-llvm-version", "minicore-compile-flags", diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 867331bf7d13c..574d7618703d2 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -360,7 +360,7 @@ impl TestCx<'_> { Some(ref version) => { writeln!( self.stdout, - "NOTE: compiletest thinks it is using LLDB version {}", + "NOTE: compiletest thinks it is using LLDB version: {:?}", version ); } diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 174ec9381f6c9..59bed76bdb510 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,4 +1,6 @@ -use crate::debuggers::{extract_gdb_version, extract_lldb_version}; +use semver::Version; + +use crate::debuggers::{LldbVersion, extract_gdb_version, extract_lldb_version}; use crate::is_test; #[test] @@ -48,12 +50,18 @@ fn test_extract_gdb_version() { #[test] fn test_extract_lldb_version() { // Apple variants - assert_eq!(extract_lldb_version("LLDB-179.5"), Some(179)); - assert_eq!(extract_lldb_version("lldb-300.2.51"), Some(300)); + assert_eq!(extract_lldb_version("LLDB-179.5"), Some(LldbVersion::Apple([179, 5, 0, 0]))); + assert_eq!(extract_lldb_version("lldb-300.2.51"), Some(LldbVersion::Apple([300, 2, 51, 0]))); // Upstream versions - assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some(600)); - assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some(900)); + assert_eq!( + extract_lldb_version("lldb version 6.0.1"), + Some(LldbVersion::Llvm(Version::new(6, 0, 1))) + ); + assert_eq!( + extract_lldb_version("lldb version 9.0.0"), + Some(LldbVersion::Llvm(Version::new(9, 0, 0))) + ); } #[test] diff --git a/tests/debuginfo/captured-fields-1.rs b/tests/debuginfo/captured-fields-1.rs index 2d8872aa02413..ddce4a3da1144 100644 --- a/tests/debuginfo/captured-fields-1.rs +++ b/tests/debuginfo/captured-fields-1.rs @@ -1,7 +1,9 @@ //@ compile-flags:-g //@ edition:2021 //@ ignore-backends: gcc -//@ min-lldb-version: 2100 +//@ min-apple-lldb-version: 2210 +//@ min-llvm-lldb-version: 21.0.0 + // === GDB TESTS =================================================================================== //@ gdb-command:run diff --git a/tests/debuginfo/constant-ordering-prologue.rs b/tests/debuginfo/constant-ordering-prologue.rs index 65a5d39a858a4..ccde9ca58a7a3 100644 --- a/tests/debuginfo/constant-ordering-prologue.rs +++ b/tests/debuginfo/constant-ordering-prologue.rs @@ -1,4 +1,5 @@ -//@ min-lldb-version: 310 +//@ min-apple-lldb-version: 310 +//@ min-llvm-lldb-version: 3.1.0 //@ compile-flags:-g //@ ignore-backends: gcc diff --git a/tests/debuginfo/dummy_span.rs b/tests/debuginfo/dummy_span.rs index 6cf79c46d9a9e..c0b7913bdefe0 100644 --- a/tests/debuginfo/dummy_span.rs +++ b/tests/debuginfo/dummy_span.rs @@ -1,4 +1,5 @@ -//@ min-lldb-version: 310 +//@ min-apple-lldb-version: 310 +//@ min-llvm-lldb-version: 3.1.0 //@ compile-flags:-g // FIXME: Investigate why test fails without SimplifyComparisonIntegral pass. diff --git a/tests/debuginfo/lexical-scope-in-match.rs b/tests/debuginfo/lexical-scope-in-match.rs index fda7223760f0b..57d11916fa933 100644 --- a/tests/debuginfo/lexical-scope-in-match.rs +++ b/tests/debuginfo/lexical-scope-in-match.rs @@ -1,7 +1,8 @@ //@ compile-flags:-g //@ disable-gdb-pretty-printers //@ ignore-backends: gcc -//@ min-lldb-version: 2100 +//@ min-apple-lldb-version: 2100 +//@ min-llvm-lldb-version: 21.0.0 // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/zst-interferes-with-prologue.rs b/tests/debuginfo/zst-interferes-with-prologue.rs index 0f2c5cf8492d8..ba58cc86169ac 100644 --- a/tests/debuginfo/zst-interferes-with-prologue.rs +++ b/tests/debuginfo/zst-interferes-with-prologue.rs @@ -1,4 +1,5 @@ -//@ min-lldb-version: 310 +//@ min-apple-lldb-version: 310 +//@ min-llvm-lldb-version: 3.1.0 //@ compile-flags:-g //@ ignore-backends: gcc