Commits

4a7578b82d19d6b51469b88ec576755f503d2f3a
Switch branches/tags
All users
All time
April 2026
Su Mo Tu We Th Fr Sa
29 30 31 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 1 2
3 4 5 6 7 8 9

Commits on April 13, 2026

  1. Add fuzzing harness: cargo-fuzz targets and deterministic smoke tests
    Lexer fuzzer, parser fuzzer (cargo fuzz), seed corpus, and
    deterministic smoke tests (10K random ASCII through lexer, 5K
    through parser, 5K Fortran fragment combinations through parser).
    mfwolffe committed
  2. Fix parser infinite loop on implicit program followed by explicit unit
    parse_implicit_program returned without consuming the END PROGRAM
    tokens. parse_file re-entered parse_program_unit at the same
    position, creating an infinite loop on inputs like:
      type :: t / end type / program p / end program
    
    Root cause: parse_unit_body breaks BEFORE the terminator tokens,
    leaving them unconsumed. parse_program calls consume_end after
    parse_unit_body, but parse_implicit_program did not.
    
    Found by fuzz smoke test with randomized Fortran fragments.
    mfwolffe committed
  3. Add cross-optimization ABI matrix tests
    Compile modules at O0 and consumer at O2 (and vice versa, and
    O0/Ofast combinations) to verify ABI consistency across opt levels.
    mfwolffe committed
  4. Add circular dependency detection tests and multi-file ERROR_EXPECTED
    Extend multi-file test path to handle ERROR_EXPECTED: when a segment
    fails to compile, check if the error matches the expected substring.
    Add direct and indirect circular USE dependency negative tests.
    mfwolffe committed
  5. Add 22 negative tests for sema diagnostics
    Pure constraints (I/O, STOP, ERROR STOP, SAVE, impure call,
    nonlocal write), intent(in), PARAMETER assignment, pointer/target,
    NULLIFY, allocatable/pointer exclusion, deferred-length,
    ALLOCATE/DEALLOCATE, duplicate label, undefined GOTO, USE of
    missing module, elemental scalar args, PASS+NOPASS conflict.
    mfwolffe committed
  6. Preserve module-visible functions in dead function elimination
    DeadFuncElim incorrectly removed module-public functions that had
    no callers within the same TU. These functions are callable from
    other translation units and must be kept. Guard on internal_only.
    mfwolffe committed
  7. Add declarative multi-file test format to run_programs harness
    !--- file: markers split a single .f90 into named segments.
    MULTIFILE_LINK annotation controls compilation/link order.
    Harness compiles each segment to .o, links with runtime, runs,
    and applies standard CHECK annotations.
    
    Seven multifile test programs cover: basic module, allocatable
    array, derived type, USE ONLY, USE rename, PARAMETER constants,
    and three-level module chain.
    mfwolffe committed
  8. mfwolffe committed

Commits on April 12, 2026

  1. Multi-source compilation: afs a.f90 b.f90 -o program
    When given multiple .f90 files, the driver scans for MODULE/USE
    dependencies, topologically sorts the files, compiles each in
    order to a temp .o + .amod (with -I pointing at the temp dir
    so earlier .amods are found), then links all .o files into the
    output binary. Files can be given in any order on the command
    line — the dependency scanner determines the correct order.
    
    Three-file chain test: app.f90 mid.f90 base.f90 given in wrong
    order → compiles base first, then mid, then app → prints 42.
    mfwolffe committed
  2. Add dependency scanner and topological sort
    New src/driver/dep_scan.rs: line-by-line scan for MODULE/USE,
    dependency graph construction, Kahn's algorithm topo sort with
    cycle detection. Intrinsic modules (iso_c_binding etc.) skipped.
    
    4 unit tests: simple scan, chain ordering, cycle error, diamond
    pattern.
    mfwolffe committed
  3. Add cross-TU multi-file compilation test harness
    New tests/multifile.rs with 7 scenarios: basic module var +
    procedure, allocatable array, derived type, PARAMETER constants,
    USE ONLY, USE rename, and module-default PRIVATE. Each test
    writes two .f90 files, compiles separately with -c and -I,
    links, runs, and checks output.
    mfwolffe committed
  4. Diagnose USE of non-existent module
    Return a SemaError when find_module_scope + .amod loading both
    fail. Message includes the module name and the .amod filename
    searched for.
    mfwolffe committed
  5. Enforce standalone PRIVATE/PUBLIC module access statements
    Parse standalone PRIVATE / PUBLIC in module body as
    Decl::AccessDefault. The resolver calls set_default_access
    so all subsequent declarations inherit the module's default
    visibility. .amod correctly filters private symbols.
    mfwolffe committed
  6. Resolve Name references in PARAMETER initializers
    eval_const_int_expr now accepts a SymbolTable ref and resolves
    Expr::Name by looking up const_value in the current scope chain.
    HALF = MAX_SIZE / 2 folds correctly: .amod shows = 512, consumer
    prints 512.
    mfwolffe committed
  7. Serialize and inline PARAMETER constants across TUs
    resolve.rs: fold integer PARAMETER initializers into
    sym.const_value via eval_const_int_expr.
    
    amod.rs reader: strip = value from @param type string before
    parsing TypeInfo.
    
    lower.rs: install_globals_as_locals now scans the SymbolTable
    module scope for symbols not in the globals map (PARAMETERs),
    so the inline_const path fires for cross-TU parameters.
    
    Limitation: PARAMETERs whose initializer involves Name
    references (e.g., HALF = MAX_SIZE / 2) don't fold yet.
    mfwolffe committed
  8. Fix char(len=*) hidden-length across compilation units
    The .amod writer inferred hidden_char_lens from the procedure
    scope's arg types instead of the empty placeholder map. The
    consumer now extracts char_len_star_params from loaded .amod
    interfaces and passes them to lower_file so call sites append
    the hidden lengths correctly.
    
    Two char(len=*) args across TU boundaries now work: 'Hello World'.
    mfwolffe committed
  9. Multi-file compilation via .amod module files
    End-to-end: afs -c module.f90 produces .o + .amod; afs -c main.f90
    -I<dir> reads the .amod, resolves USE, and emits references to the
    module's linker symbols; ld links both .o files into a working binary.
    
    resolve.rs: lazy-loads .amod files when find_module_scope misses.
    Creates synthetic module scopes, populates symbols + type layouts.
    Returns loaded ModuleInterface objects for globals extraction.
    
    lower.rs: accepts external_globals from .amod-loaded modules.
    install_globals_as_locals emits global_addr references that the
    linker resolves from the module's .o file.
    
    driver: skips _main wrapper when no __prog_* function exists
    (module-only .o files). Extracts external globals from loaded
    .amod interfaces and passes them to lower_file.
    mfwolffe committed
  10. Implement .amod v2 reader with round-trip test
    Line-by-line parser for #!amod 2 files. Returns ModuleInterface
    with variables (with IR symbol names), procedures (with full arg
    signatures, intents, optional), type layouts (with fields,
    bindings, tags), and dependencies. Round-trip test verifies
    parsing of a representative physics module.
    mfwolffe committed
  11. Thread module_search_paths into resolve_file
    resolve_file now accepts &[PathBuf] for -I directories. The
    driver passes opts.module_search_paths; all other callers
    pass &[] (single-file mode). Prepares for .amod lazy loading
    in process_uses.
    mfwolffe committed
  12. Rewrite .amod writer to v2 format
    Full v2 spec: #!amod 2 magic, sha256 checksum, abi target,
    @uses dependencies, @var/@param split with @ir symbol names,
    full procedure arg signatures (types, intents, optional) by
    walking child scopes, @abi lines with cc and register
    assignments per AAPCS64, @hint lines (leaf, no_globals, cost),
    @type with @layout/@field/@binds/@final/@tag/@extends,
    @interface for generics.
    
    Innovations: explicit ABI annotations, optimization hints,
    linker symbol names, type layout preservation, polymorphic
    type tags — none of which gfortran/flang/ifort expose.
    mfwolffe committed
  13. Emit .amod module interface files on -c
    New src/sema/amod.rs with write_amod: serializes a module's
    public variables (with global symbol names), procedures (with
    pure/elemental), parameters (with const_value), and derived
    types (with field layouts) to a human-inspectable text format.
    
    The driver calls it for each MODULE in the compilation unit
    when -c mode writes a .o file. The .amod lands alongside the
    .o with the module name as the filename.
    mfwolffe committed
  14. Expose ModuleGlobalInfo from lower_file
    Make ModuleGlobalInfo pub(crate) and return it alongside the
    IR Module from lower_file. The driver and .amod writer will
    use it to serialize module interfaces for multi-file builds.
    mfwolffe committed
  15. Add -I flag for module search paths
    Parse -I <dir> and -Idir in Options::from_args. Stored as
    module_search_paths: Vec<PathBuf> for the .amod reader to
    use when resolving USE statements across compilation units.
    mfwolffe committed
  16. Emit .globl for module globals and COMMON slots
    Module globals (afs_mod_*) and COMMON slots (afs_common_*)
    need external linkage for multi-file compilation. Non-module
    globals (SAVE-promoted locals) stay .private_extern.
    mfwolffe committed
  17. mfwolffe committed
  18. Emit 32-byte StringDescriptor for module deferred-length chars
    Module character(len=:), allocatable globals were emitted as
    the element type size (1-8 bytes). The deferred-length path
    needs a 32-byte StringDescriptor so the pointer + length
    fields are both present. Add deferred_char flag to
    ModuleGlobalInfo and handle it in both the emit and install
    paths.
    mfwolffe committed