DO, PROG, etc. establish an implicit block named nil around their bodies. The CLHS doesn’t provide a list of all standard macros that do this. So far the ones I know about:
DO
DO*
PROG
PROG*
LOOP
DOLIST
DOTIMES
DO-SYMBOLS
DO-ALL-SYMBOLS
DO-EXTERNAL-SYMBOLS
Are there any other standard CL macros or special forms that establish implicit nil blocks?
I believe the list in the question is complete. My evidence for this is experimental, not derived from checking every page of CLHS; here’s what I did, for the benefit of anyone who wants to check I didn’t miss anything important. There’s a list of caveats right at the end.
First, a simple function to check a macro expansion for having a block called NIL. It will find NIL blocks that aren’t at the top level. It may have false positives, so the output needs checking by hand.
Then I picked the CL implementation I had most conveniently to hand, which happens to be CLISP, and did this:
which gave me the following list (which is in no particular order, includes repeated symbols, and includes some but not all symbols that are defined in CLHS as special operators):
Then I took these, together with the special operators listed in CLHS section 3.1.2.1.2.1, removed the ones that aren’t mentioned in CLHS, removed duplicates, cooked up a typical invocation for each (more than one in some cases), and then checked the result of calling MACROEXPAND-1 and MACROEXPAND on each of these:
This reports, for any of the candidate macro invocations, (1) whether it expanded directly (via MACROEXPAND-1) to something with a (BLOCK NIL …) in it, and (2) if not, whether it expanded indirectlY (via MACROEXPAND) to something with a (BLOCK NIL …) in it. It shows the macro expansions so that you can make sure they aren’t false positives.
Here’s the result (I’ve snipped out a few warning messages):
which, as you can see, includes all the symbols listed in the original question and no others.
Ways in which this could have gone wrong: (1) Whether invoking a given macro produces a nil block might depend on the details of the invocation. I deliberately chose nice simple invocations for all the macros, and it’s possible that (e.g.) some more baroque instance of DEFCLASS might do something that creates a nil block. (2) I might have missed some items in the list of macros. (My candidate list is kinda-sorta in the order output by CLISP, but I rearranged it a bit to put related macros together.) (3) CLISP might be non-standard in relevant ways.
I’m fairly confident that none of those is actually the case in ways that invalidate my results. Turning “fairly confident” into “near-absolutely certain” would probably mean doubling the amount of work this required :-).