Should a compiler give compile-time errors or warnings for syntactically valid but logically invalid code?

With some programming languages, a compiler may reject code that, while otherwise syntactically valid, is readily determined to be logically invalid through static analysis.

An example is Visual C++ giving a compile-time error if a program contains a constant division by zero. While division by zero is undefined under the C++ standard, meaning that the compiler and program can technically do anything in a situation like this, GCC and Clang do not consider this a compile-time error and will produce a warning instead. (Indeed, this question was inspired by a Stack Overflow question on whether it's better to return an error instead of a warning when a C++ compiler encounters a constant division by zero.)

Other examples include C# prohibiting statements that do not do anything ("Only assignment, call, increment, decrement, and new object expressions can be used as a statement") and Java treating many types of unreachable code as compile-time errors ("It is a compile-time error if a statement cannot be executed because it is unreachable.").

In all of these cases, the code is otherwise syntactically valid and can technically be compiled, but the compiler refuses to do so.

Is it better to completely reject these sorts of logical mistakes in code at compile time, or to compile the program anyway and output warnings instead? In other words, should the compiler shield the programmer from obvious mistakes by refusing to compile code that is almost certainly logically wrong, or should it just compile any syntactically-valid code as a matter of principle, warning the programmer if it runs into suspicious code?