Skip to content

Commit 1207209

Browse files
committed
fix(semantic): accept clang's -F with a separated framework path
Clang's -F is a JoinedOrSeparate option, so `-F /Frameworks` and `-F/Frameworks` name the same framework search path. The flag table spelled it as a prefix match, which only covers the joined form. Given the separated form, the operand fell through to source classification, was rejected as a binary source, and was dropped from the entry -- the recorded command kept a standalone `-F` that no compiler can consume, and the search path was silently lost. SwiftPM emits the separated spelling on macOS, which is how this surfaced; it reproduces on any captured invocation and through parse-sh. Spelling it `-F{ }*` matches both forms, the same way gcc.yaml already spells -I, -D and -L, and swift.yaml and nasm.yaml already spell -F. The four families that extend clang inherit the fix; none override -F. Requirement: output-compilation-entries (flags that configure compiling are kept in the entry). Closes #715
1 parent e29efe1 commit 1207209

7 files changed

Lines changed: 80 additions & 11 deletions

File tree

build-support/compilers-codegen/tests/snapshots/snapshots__snapshot_flags_armclang.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
source: build-support/compilers-codegen/tests/snapshots.rs
3-
expression: "generate_flag_file(\"armclang\")"
3+
expression: generated
44
---
55
// Generated from compilers/armclang.yaml -- DO NOT EDIT
66
static ARMCLANG_FLAGS: [FlagRule; 207] = [
@@ -172,7 +172,7 @@ static ARMCLANG_FLAGS: [FlagRule; 207] = [
172172
FlagRule::new(FlagPattern::Exactly("-MQ", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
173173
FlagRule::new(FlagPattern::Exactly("-CC", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
174174
FlagRule::new(FlagPattern::Prefix("-no", 0), ArgumentKind::Other(PassEffect::None)),
175-
FlagRule::new(FlagPattern::Prefix("-F", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
175+
FlagRule::new(FlagPattern::ExactlyWithGluedOrSep("-F"), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
176176
FlagRule::new(FlagPattern::Exactly("-Z", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
177177
FlagRule::new(FlagPattern::Prefix("-a", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
178178
FlagRule::new(FlagPattern::Prefix("-r", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Linking))),

build-support/compilers-codegen/tests/snapshots/snapshots__snapshot_flags_clang.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
source: build-support/compilers-codegen/tests/snapshots.rs
3-
expression: "generate_flag_file(\"clang\")"
3+
expression: generated
44
---
55
// Generated from compilers/clang.yaml -- DO NOT EDIT
66
static CLANG_FLAGS: [FlagRule; 199] = [
@@ -164,7 +164,7 @@ static CLANG_FLAGS: [FlagRule; 199] = [
164164
FlagRule::new(FlagPattern::Exactly("-MQ", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
165165
FlagRule::new(FlagPattern::Exactly("-CC", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
166166
FlagRule::new(FlagPattern::Prefix("-no", 0), ArgumentKind::Other(PassEffect::None)),
167-
FlagRule::new(FlagPattern::Prefix("-F", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
167+
FlagRule::new(FlagPattern::ExactlyWithGluedOrSep("-F"), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
168168
FlagRule::new(FlagPattern::Exactly("-Z", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
169169
FlagRule::new(FlagPattern::Prefix("-a", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
170170
FlagRule::new(FlagPattern::Prefix("-r", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Linking))),

build-support/compilers-codegen/tests/snapshots/snapshots__snapshot_flags_cray_cc.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
source: build-support/compilers-codegen/tests/snapshots.rs
3-
expression: "generate_flag_file(\"cray_cc\")"
3+
expression: generated
44
---
55
// Generated from compilers/cray_cc.yaml -- DO NOT EDIT
66
static CRAY_CC_FLAGS: [FlagRule; 200] = [
@@ -165,7 +165,7 @@ static CRAY_CC_FLAGS: [FlagRule; 200] = [
165165
FlagRule::new(FlagPattern::Exactly("-MQ", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
166166
FlagRule::new(FlagPattern::Exactly("-CC", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
167167
FlagRule::new(FlagPattern::Prefix("-no", 0), ArgumentKind::Other(PassEffect::None)),
168-
FlagRule::new(FlagPattern::Prefix("-F", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
168+
FlagRule::new(FlagPattern::ExactlyWithGluedOrSep("-F"), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
169169
FlagRule::new(FlagPattern::Exactly("-Z", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
170170
FlagRule::new(FlagPattern::Prefix("-a", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
171171
FlagRule::new(FlagPattern::Prefix("-r", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Linking))),

build-support/compilers-codegen/tests/snapshots/snapshots__snapshot_flags_ibm_xl.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
source: build-support/compilers-codegen/tests/snapshots.rs
3-
expression: "generate_flag_file(\"ibm_xl\")"
3+
expression: generated
44
---
55
// Generated from compilers/ibm_xl.yaml -- DO NOT EDIT
66
static IBM_XL_FLAGS: [FlagRule; 225] = [
@@ -190,7 +190,7 @@ static IBM_XL_FLAGS: [FlagRule; 225] = [
190190
FlagRule::new(FlagPattern::Exactly("-MQ", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
191191
FlagRule::new(FlagPattern::Exactly("-CC", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Preprocessing))),
192192
FlagRule::new(FlagPattern::Prefix("-no", 0), ArgumentKind::Other(PassEffect::None)),
193-
FlagRule::new(FlagPattern::Prefix("-F", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
193+
FlagRule::new(FlagPattern::ExactlyWithGluedOrSep("-F"), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
194194
FlagRule::new(FlagPattern::Exactly("-Z", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
195195
FlagRule::new(FlagPattern::Prefix("-a", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
196196
FlagRule::new(FlagPattern::Prefix("-r", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Linking))),

build-support/compilers-codegen/tests/snapshots/snapshots__snapshot_flags_intel_cc.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
source: build-support/compilers-codegen/tests/snapshots.rs
3-
expression: "generate_flag_file(\"intel_cc\")"
3+
expression: generated
44
---
55
// Generated from compilers/intel_cc.yaml -- DO NOT EDIT
66
static INTEL_CC_FLAGS: [FlagRule; 262] = [
@@ -227,7 +227,7 @@ static INTEL_CC_FLAGS: [FlagRule; 262] = [
227227
FlagRule::new(FlagPattern::Prefix("-no", 0), ArgumentKind::Other(PassEffect::None)),
228228
FlagRule::new(FlagPattern::Prefix("-x", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
229229
FlagRule::new(FlagPattern::Exactly("-V", 0), ArgumentKind::Other(PassEffect::InfoAndExit)),
230-
FlagRule::new(FlagPattern::Prefix("-F", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
230+
FlagRule::new(FlagPattern::ExactlyWithGluedOrSep("-F"), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
231231
FlagRule::new(FlagPattern::Exactly("-Z", 1), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
232232
FlagRule::new(FlagPattern::Prefix("-a", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Compiling))),
233233
FlagRule::new(FlagPattern::Prefix("-r", 0), ArgumentKind::Other(PassEffect::Configures(CompilerPass::Linking))),

crates/semantic/compilers/clang.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ slash_prefix: false
3838
flags:
3939
- match: {pattern: "--prefix=*"}
4040
result: configures_preprocessing
41-
- match: {pattern: "-F*"}
41+
- match: {pattern: "-F{ }*"}
4242
result: configures_compiling
4343
- match: {pattern: "-ObjC"}
4444
result: none

tests/integration/tests/cases/semantic.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,75 @@ fn clang_cl_inherits_msvc_per_warning_options() -> Result<()> {
873873
Ok(())
874874
}
875875

876+
// Requirements: output-compilation-entries
877+
//
878+
// Regression test for issue #715: Clang's `-F` (framework search path) is a
879+
// JoinedOrSeparate option, so `-F /Frameworks` and `-F/Frameworks` are the same
880+
// invocation. Bear only recognized the joined spelling, so the separated operand
881+
// fell through to source classification and was dropped, leaving a standalone
882+
// `-F` that no compiler can consume. SwiftPM emits the separated form on macOS,
883+
// which is how this surfaced.
884+
//
885+
// Both spellings are checked in one run, each on its own translation unit, so the
886+
// pair cannot drift apart. `bear semantic` runs the interpreter without executing
887+
// clang, so no toolchain is required and the executable name can be a bare `clang`.
888+
#[test]
889+
fn clang_framework_search_path_preserves_separated_and_joined_operand() -> Result<()> {
890+
let env = TestEnvironment::new("clang_framework_search_path")?;
891+
let temp_dir = env.test_dir().to_str().unwrap();
892+
893+
let clang = "clang";
894+
895+
let event_separated = json!({
896+
"executable": clang,
897+
"arguments": [clang, "-F", "/Frameworks", "-c", "separated.cpp"],
898+
"working_dir": temp_dir,
899+
"environment": {}
900+
});
901+
let event_joined = json!({
902+
"executable": clang,
903+
"arguments": [clang, "-F/Frameworks", "-c", "joined.cpp"],
904+
"working_dir": temp_dir,
905+
"environment": {}
906+
});
907+
908+
let events = format!("{}\n{}", event_separated, event_joined);
909+
910+
env.create_source_files(&[
911+
("events.json", &events),
912+
("separated.cpp", "int main() { return 0; }"),
913+
("joined.cpp", "int main() { return 0; }"),
914+
])?;
915+
916+
env.run_bear_success(&["semantic", "--input", "events.json", "--output", "compile_commands.json"])?;
917+
918+
let db = env.load_compilation_database("compile_commands.json")?;
919+
db.assert_count(2)?;
920+
921+
db.assert_contains(&compilation_entry!(
922+
file: "separated.cpp".to_string(),
923+
directory: temp_dir.to_string(),
924+
arguments: vec![
925+
clang.to_string(),
926+
"-F".to_string(), "/Frameworks".to_string(),
927+
"-c".to_string(),
928+
"separated.cpp".to_string(),
929+
]
930+
))?;
931+
db.assert_contains(&compilation_entry!(
932+
file: "joined.cpp".to_string(),
933+
directory: temp_dir.to_string(),
934+
arguments: vec![
935+
clang.to_string(),
936+
"-F/Frameworks".to_string(),
937+
"-c".to_string(),
938+
"joined.cpp".to_string(),
939+
]
940+
))?;
941+
942+
Ok(())
943+
}
944+
876945
// Requirements: output-compilation-entries
877946
//
878947
// Vala's `valac` is a transpiler-driver: it parses GNU-style (GOption) flags,

0 commit comments

Comments
 (0)