For a compiler, error messages about the code being compiled are the "normal" output, so they should be written to stdout, not stderr. The only messages that should be written to stderr would be about errors in running the compiler itself (e.g., if a file that makes up part of the compiler can't be found, so the compiler couldn't run).
The same basic guideline applies to most other programs: if the "message" in question is part of the "standard" output of that program, and a user would normally expect it to be included when/if they redirect the output, then it should be written to standard output. Standard error is intended for messages the user will normally want/need to see even if they have standard output redirected to a file -- primarily those saying that the program couldn't run, so there is no output, or if there is that it's likely to be incomplete or invalid.