Geoff Chappell - Software Analyst
Detection of the __compileBreak keyword causes the compiler to break to the debugger if the /Bd option is active or if the environment variable _CL_DEBUGBREAK exists (whatever its value). Without either of these preparations, the keyword is simply ignored.
The break to the debugger occurs within the preprocessor’s lowest-level code for reading tokens, such that continuation will soon see the compiler retrieve the next token. Its obvious use is for problems whose circumstances of occurrence are known in terms of a position in source code but whose cause needs to be investigated with the precision of a debugger. As such, __compileBreak is presumably intended only as an aid to Microsoft’s own debugging of its compiler. This may explain its being left undocumented: who but Microsoft’s own programmers would ever have good cause to debug Microsoft’s compiler, and even if they do, and could, why should Microsoft help them? (In this context, note that the C1XX option -debugBreak is also undocumented.)
The __compileBreak keyword can be placed, and be recognised, anywhere that the compiler works with tokens produced by the usual preprocessing of source text. Only the very lowest-level code for reading tokens ever sees any token that represents __compileBreak as a keyword. Whether or not this code breaks to the debugger, it absorbs the token. The instructions after the break are those that will read the next token. To higher-level code, and particularly for any syntax at the level of tokens, the __compileBreak may as well have been white space. For instance,
class __declspec __compileBreak (novtable) Test;
There is no recognition of __compileBreak (or of any other keyword) where source code is parsed without tokenisation, as in the early parts of preprocessor directives (and in the whole of some). For instance, in
#error __compileBreak error message text
the characters of __compileBreak are like any other characters of text for the error message: the compiler simply does not bother with tokens in a #error directive (which is also why macros are not expanded in a #error message, whatever the product documentation states to the contrary). Similarly, not only does
# __compileBreak pragma managed
not break to the debugger, but the __compileBreak is rejected fatally as an invalid preprocessor command. By contrast,
#pragma __compileBreak managed
does break, because everything after the #pragma is handled as tokens.
There is also no recognition of __compileBreak (or, again, of any other keyword) in areas of source code that are tokenised, but according to some scheme of Microsoft’s own rather than to the usual rules of the C++ language. It is not presently known how widely such variation is implemented. The known case applies inside attribute blocks, which essentially have their own preprocessor (not that the product documentation cares to alert programmers to this). In an attribute block, __compileBreak is simply not a keyword, but is tokenised as an identifier like any other. Thus, in
[__compileBreak, module __compileBreak (name = "Test")];
the first occurrence is interpreted as naming an attribute and the second is rejected as unexpected.