I.e. function without attribute compile -> OK, function with ICACHE_RAM_ATTR compile -> error.
I then thought maybe it would help if I put the interrupt handler definition above the setup code that called attachInterrupt. I had got used to the compiler not normally worrying about definition order.
That was the trick. Now compiled OK and crashes gone away in the runtime.
Not a problem now I know what to do, but I am curious why adding the attribute changes the compiler behaviour and whether there any other ordering rules to worry about.