← board

Warn when a routine directive is accepted but cannot be honored

The situation

Routine directives fall into three groups today (measured, and now tabulated in docs/language/dialect.md#routine-directives):

Only interrupt says anything when it cannot be honored:

error: interrupt directive: raw hardware-vector codegen implemented for riscv32
(esp32c3) and xtensa Call0 (esp32s3) only. Use `iram;` for an IDF-registered ISR.

Everything else is silent. iram on x86-64 compiles clean. So does cdecl on a routine — and there the silence is defensible (the convention is the target's, so the marker is documentation) but a reader cannot tell the two cases apart.

inline is the interesting one

ProcInline is written and never read. if declInline then ProcInline[procIdx] := True in parser.inc is its only mention outside the False initialiser in symtab.inc; no backend, IR pass or inliner consults it. The -O2 inliner decides purely on shape — a function, scalar result, at most six scalar by-value params, not external/cdecl/variadic/generator/stackless.

Measured with PXXDBG=a.inline at -O2 on a marked and an unmarked routine of the same shape:

PXXDBG a.inline RETAIN twice  shape=1 params=1     { NO inline directive }
PXXDBG a.inline RETAIN thrice shape=1 params=1     { inline; }

Identical. So inline neither helps nor hurts, and a routine that does not qualify is not inlined however loudly it is marked. That matches every modern compiler — the directive is a hint and the optimizer already knows — but it means a user writing inline on a six-parameter procedure returning a record is being told nothing while getting nothing.

Proposal

A single warning: directive 'X' is ignored here diagnostic, off by default or under an existing strictness flag (--strict-fpc's umbrella is the natural home — see [[project_strict_fpc_umbrella_and_lax_default]]), covering:

Deliberately NOT proposed: warning on the hint directives (deprecated/platform/…). Those are meant to be inert until usage warnings exist, and warning about them would fire on ordinary FPC source.

Priority

Raised 30 -> 60 by the user, 2026-08-03: "raise the prio on that ticket though.. feedback is informative". The point is general, not about this ticket alone — a diagnostic that tells the user what the compiler actually did is worth more than its size suggests, and should not be ranked as cosmetic just because it changes no generated code.

Gate

Each inert directive warns under the flag and stays silent without it; the corpora and lib/rtl build with no new warnings in the default mode; self-host fixedpoint byte-identical.

Implemented 2026-08-05 — --warn-ignored-directives

Opt-in, diagnostic only, silent by default (these are all legal FPC source and warning unconditionally would fire on every ordinary unit). Follows the --warn-uses-leak pattern rather than going under --strict-fpc: this reports what the compiler did, it does not change what it accepts, so it does not belong in the FPC-parity umbrella.

$ pascal26 -O2 --warn-ignored-directives dir1.pas d1
dir1.pas:2: warning: directive 'cdecl' ignored here: the calling convention is
  the target's and is not selectable per routine, so P already uses it; the
  marker is documentation only
dir1.pas:3: warning: directive 'register' ignored here: ...
dir1.pas:4: warning: directive 'iram' ignored here: IRAM placement exists on
  the ESP targets (xtensa, riscv32) only; this target has no separate
  instruction RAM to place R in
dir1.pas:5: warning: directive 'stackful' ignored here: it is the default
  strategy, so it selects nothing
dir1.pas:6: warning: directive 'inline' ignored here: the inliner takes at most
  six by-value scalar parameters and Big has 7
dir1.pas:7: warning: directive 'inline' ignored here: only a function with a
  scalar result is inlined, and NotFn is a procedure

Covers cdecl, register, iram off the ESP targets, stackful, reintroduce, and inline. Each message says why, as the ticket asked — "the calling convention is the target's", not "dropped".

Hint directives are excluded as specified.

inline: only causes that are actually established

The ticket wanted "which rule it broke". The flag reports the four causes knowable at the declaration — optimisation level below -O2, a procedure rather than a function, assembler/generator/async/stackless, and more than six parameters. It deliberately does not claim "your body is too complex": the body has not been parsed at that point, and the eligibility gate is ~30 bare Exits in three retention functions with no reason recorded. Threading a reason out of those is a real change to the inliner and is not worth risking for a diagnostic; asserting an unestablished cause would be exactly the failure this ticket exists to fix.

So a routine that fails only on body shape gets no warning today. The control case in the test (Ok, one param, inlinable) correctly stays silent at -O2 and correctly warns at -O0 with the optimisation-level reason.

Verified

Test: test/test_warn_ignored_directives.pas — asserts silence without the flag, exactly 6 warnings with it, and that the program still runs. Docs are Track D's: [[task-d-document-warn-ignored-directives]].

Gate: testmgr --tier limited 1587/1587 GREEN + self-host fixedpoint.

Resolved: 277ab2e66

Log