← board

C preprocessor silently ignores #include_next (and every unknown directive)

Repro

mkdir -p a b
printf '#include_next <foo.h>\n' > a/foo.h
printf 'typedef unsigned int my_t;\n#define FOO_B 1\n' > b/foo.h
printf '#include <foo.h>\nint main(void){ my_t x = FOO_B; return (int)x; }\n' > m.c
pascal26 -Ia -Ib --dump-cpp m.c     # nothing from b/foo.h appears
pascal26 -Ia -Ib m.c m              # fails later, far from the cause
printf '#bogus_directive\nint main(void){return 0;}\n' > z.c
pascal26 z.c z                      # compiles, no diagnostic

Real-world chain

ESP toolchain include order (as gcc uses it): lib/gcc/riscv32-esp-elf/15.2.0/include, include-fixed, riscv32-esp-elf/include (newlib). gcc's include/stdint.h is #if __STDC_HOSTED__ / # include_next <stdint.h> (pxx predefines STDC_HOSTED=1, cpreproc.inc:3658). The include_next is dropped, so the preprocessed esp_netif.h has no uint8_t/uint32_t typedef anywhere. struct esp_ip4_addr { uint32_t addr; } and uint8_t type; silently lose their members, and the first access (esp_netif_ip_addr_copy in esp_netif_ip_addr.h:157) reports no member named 'type'.

Workaround that proves it: put newlib's dir before gcc's (CENSUS_NEWLIB_FIRST=1 tools/idf_census.sh esp_netif in ~/museum_landkaart/async, together with the predefines ticket's prefix). Then uses esp_netif compiles.

Expected

Acceptance

The repro's dump contains typedef unsigned int my_t;, z.c fails with a directive diagnostic, and esp_netif imports with gcc's include order.