@@ -4530,11 +4530,12 @@ fn (mut g FlatGen) collect_preserved_header_file(path string, include_dirs []str
45304530 }
45314531 g.preserved_header_files_seen[real_path] = true
45324532 text := os.read_file(real_path) or { return }
4533- g.collect_inlined_c_structs(text)
4534- g.collect_inlined_c_fns(text)
4535- g.collect_inlined_c_declared_fns(text)
4533+ possible_text := c_header_possible_active_text(text, g.c_flags, g.c99_mode, g.target)
4534+ g.collect_inlined_c_structs(possible_text)
4535+ g.collect_inlined_c_fns(possible_text)
4536+ g.collect_inlined_c_declared_fns(possible_text)
45364537 mut in_block_comment := false
4537- for line in text .split_into_lines() {
4538+ for line in possible_text .split_into_lines() {
45384539 clean, next_in_block_comment := c_preprocessor_directive_scan_line(line, in_block_comment)
45394540 in_block_comment = next_in_block_comment
45404541 if c_directive_name(clean) !in ['include', 'import'] {
@@ -4558,6 +4559,186 @@ fn (mut g FlatGen) collect_preserved_header_file(path string, include_dirs []str
45584559 }
45594560}
45604561
4562+ // c_header_possible_active_text removes declarations from preprocessor branches
4563+ // known to be inactive for the current target and C flags. Unknown branches stay
4564+ // in the scan so a declaration that the real compiler may see remains authoritative.
4565+ fn c_header_possible_active_text(text string, flags []string, c99_mode bool, target pref.Target) string {
4566+ mut defined := map[string]bool{}
4567+ mut undefined := map[string]bool{}
4568+ mut uncertain := map[string]bool{}
4569+ // A preserved header inherits macros from its including source and parent
4570+ // headers. That context is not carried through this lightweight recursive
4571+ // scan, so an otherwise unknown macro must keep both branches possible.
4572+ mut external_macros_possible := true
4573+ mut i := 0
4574+ for i < flags.len {
4575+ clean := trimmed_space(flags[i])
4576+ mut definition := ''
4577+ mut is_undef := false
4578+ if clean == '-D' && i + 1 < flags.len {
4579+ definition = trimmed_space(flags[i + 1])
4580+ i++
4581+ } else if clean.starts_with('-D') {
4582+ definition = clean[2..]
4583+ } else if clean == '-U' && i + 1 < flags.len {
4584+ definition = trimmed_space(flags[i + 1])
4585+ is_undef = true
4586+ i++
4587+ } else if clean.starts_with('-U') {
4588+ definition = clean[2..]
4589+ is_undef = true
4590+ }
4591+ name := definition.all_before('=').trim_space()
4592+ if name.len > 0 {
4593+ if is_undef {
4594+ defined.delete(name)
4595+ undefined[name] = true
4596+ } else {
4597+ undefined.delete(name)
4598+ defined[name] = true
4599+ }
4600+ }
4601+ i++
4602+ }
4603+ strict_iso_mode := c_effective_strict_iso_mode(flags, c99_mode)
4604+ mut condition_known := []bool{}
4605+ mut condition_active := []bool{}
4606+ mut condition_taken_known := []bool{}
4607+ mut condition_taken := []bool{}
4608+ mut output := strings.new_builder(text.len)
4609+ mut in_block_comment := false
4610+ for line in c_join_continued_lines(text) {
4611+ clean, next_in_block_comment := c_preprocessor_directive_scan_line(line, in_block_comment)
4612+ in_block_comment = next_in_block_comment
4613+ name := c_directive_name(clean)
4614+ if name in ['ifdef', 'ifndef'] {
4615+ macro_name := c_directive_arg(clean).fields()[0] or { '' }
4616+ known, mut active := c_preprocessor_ifdef_macro_state(macro_name, defined, undefined,
4617+ uncertain, external_macros_possible, strict_iso_mode, target)
4618+ if name == 'ifndef' {
4619+ active = !active
4620+ }
4621+ condition_known << known
4622+ condition_active << (if known { active } else { true })
4623+ condition_taken_known << known
4624+ condition_taken << (if known { active } else { true })
4625+ output.writeln('')
4626+ continue
4627+ }
4628+ if name == 'if' {
4629+ known, active := c_preprocessor_condition_state(c_directive_arg(clean), defined,
4630+ undefined, uncertain, external_macros_possible, strict_iso_mode, target)
4631+ condition_known << known
4632+ condition_active << (if known { active } else { true })
4633+ condition_taken_known << known
4634+ condition_taken << (if known { active } else { true })
4635+ output.writeln('')
4636+ continue
4637+ }
4638+ if name == 'elif' && condition_known.len > 0 {
4639+ last := condition_known.len - 1
4640+ prior_known := condition_taken_known[last]
4641+ prior_taken := condition_taken[last]
4642+ known, active := c_preprocessor_condition_state(c_directive_arg(clean), defined,
4643+ undefined, uncertain, external_macros_possible, strict_iso_mode, target)
4644+ if (prior_known && prior_taken) || (known && !active) {
4645+ condition_known[last] = true
4646+ condition_active[last] = false
4647+ } else if prior_known && known {
4648+ condition_known[last] = true
4649+ condition_active[last] = true
4650+ } else {
4651+ condition_known[last] = false
4652+ condition_active[last] = true
4653+ }
4654+ if (prior_known && prior_taken) || (known && active) {
4655+ condition_taken_known[last] = true
4656+ condition_taken[last] = true
4657+ } else if prior_known && known {
4658+ condition_taken_known[last] = true
4659+ condition_taken[last] = false
4660+ } else {
4661+ condition_taken_known[last] = false
4662+ condition_taken[last] = true
4663+ }
4664+ output.writeln('')
4665+ continue
4666+ }
4667+ if name == 'else' && condition_known.len > 0 {
4668+ last := condition_known.len - 1
4669+ condition_known[last] = condition_taken_known[last]
4670+ condition_active[last] = if condition_taken_known[last] {
4671+ !condition_taken[last]
4672+ } else {
4673+ true
4674+ }
4675+ condition_taken_known[last] = true
4676+ condition_taken[last] = true
4677+ output.writeln('')
4678+ continue
4679+ }
4680+ if name == 'endif' && condition_known.len > 0 {
4681+ condition_known.delete_last()
4682+ condition_active.delete_last()
4683+ condition_taken_known.delete_last()
4684+ condition_taken.delete_last()
4685+ output.writeln('')
4686+ continue
4687+ }
4688+ mut possibly_active := true
4689+ mut definitely_active := true
4690+ for depth in 0 .. condition_known.len {
4691+ if condition_known[depth] && !condition_active[depth] {
4692+ possibly_active = false
4693+ definitely_active = false
4694+ break
4695+ }
4696+ if !condition_known[depth] {
4697+ definitely_active = false
4698+ }
4699+ }
4700+ if !possibly_active {
4701+ output.writeln('')
4702+ continue
4703+ }
4704+ if name in ['include', 'import'] {
4705+ c_preprocessor_invalidate_macro_state(mut defined, mut undefined, mut uncertain)
4706+ external_macros_possible = true
4707+ } else if name in ['define', 'undef'] {
4708+ parts := c_directive_arg(clean).fields()
4709+ if parts.len > 0 {
4710+ macro_name := parts[0].all_before('(')
4711+ if definitely_active {
4712+ uncertain.delete(macro_name)
4713+ if name == 'define' {
4714+ undefined.delete(macro_name)
4715+ defined[macro_name] = true
4716+ } else {
4717+ defined.delete(macro_name)
4718+ undefined[macro_name] = true
4719+ }
4720+ } else {
4721+ defined.delete(macro_name)
4722+ undefined.delete(macro_name)
4723+ uncertain[macro_name] = true
4724+ }
4725+ }
4726+ }
4727+ output.writeln(line)
4728+ }
4729+ return output.str()
4730+ }
4731+
4732+ fn c_preprocessor_ifdef_macro_state(name string, defined map[string]bool, undefined map[string]bool, uncertain map[string]bool, external_macros_possible bool, strict_iso_mode bool, target pref.Target) (bool, bool) {
4733+ if external_macros_possible && name !in defined && name !in undefined && name !in uncertain
4734+ && name !in ['__linux__', '__linux', 'linux', 'unix', '__APPLE__', '__MACH__', '_WIN32', '_WIN64', '__FreeBSD__', '__OpenBSD__', '__NetBSD__'] {
4735+ // An earlier include can define an otherwise unknown macro. Keep both
4736+ // branches in that case so the declaration scan never drops active code.
4737+ return false, true
4738+ }
4739+ return c_preprocessor_macro_state(name, defined, undefined, uncertain, strict_iso_mode, target)
4740+ }
4741+
45614742fn c_inline_header_text(include_arg string, vroot string, source_file string, include_dirs []string, translation_unit_uses_inttypes bool) ?CInlineHeader {
45624743 if replacement := c_system_include_replacement(include_arg, translation_unit_uses_inttypes) {
45634744 return CInlineHeader{
@@ -8378,8 +8559,8 @@ fn c_native_source_context_state(directives []string, flags []string, c99_mode b
83788559 name := c_directive_name(clean)
83798560 if name in ['ifdef', 'ifndef'] {
83808561 macro_name := c_directive_arg(clean).fields()[0] or { '' }
8381- known, mut active := c_preprocessor_macro_state (macro_name, defined, undefined ,
8382- uncertain, strict_iso_mode, target)
8562+ known, mut active := c_preprocessor_ifdef_macro_state (macro_name, defined,
8563+ undefined, uncertain, external_macros_possible , strict_iso_mode, target)
83838564 if name == 'ifndef' {
83848565 active = !active
83858566 }
@@ -8624,8 +8805,8 @@ fn c_preprocessor_condition_state(raw string, defined map[string]bool, undefined
86248805 if macro_name.len == 0 || c_header_struct_tag(macro_name) != macro_name {
86258806 return false, true
86268807 }
8627- known, mut active := c_preprocessor_macro_state (macro_name, defined, undefined, uncertain ,
8628- strict_iso_mode, target)
8808+ known, mut active := c_preprocessor_ifdef_macro_state (macro_name, defined, undefined,
8809+ uncertain, external_macros_possible, strict_iso_mode, target)
86298810 if negated {
86308811 active = !active
86318812 }
0 commit comments