Hi Michael, Johannes,
I’m creating a new thread since my question would be slightly out-of-topic in the original discussion about function attributes:
If my reading of the C standard is correct, it is UB to redefine libc functions: “If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.” (http://port70.net/~nsz/c/c11/n1570.html#7.1.3p2)
Michael mentioned this in the original thread:
Frontends are supposed to add a “nobuiltin” attribute to functions that do not correspond to the semantics of the C library function with the same name.
I don’t think it was implied that the frontend can argue about the semantics of a function, was it?
There is a "-fno-builtin- family of clang CLI options that forbid the compiler to convert libc calls into intrinsics. Is it correct to say that the only way for the user to define their
memcpy and avoid UB is to pass “-fno-builtin-memcpy” to the compiler?
This is for (mostly) intended for front-ends of languages that are not
C/C++. In Rust for instance, one can define a function "printf" that
is unrelated with the C library function.
As for Clang, a C/C++/Objective-C frontend, it adheres to the
C/C++/Objectice-C specification where those function names are
reserved. I recommend not to redefine those.
I am not sure what the purpose of the -fno-builtin-* flags are, but I
suggest to avoid them as they are non-standard. For Clang, the only
reason for their existence is probably compatibility with gcc.
The C standard is written assuming that a C standard library implementation appeared fully formed out of the aether. It is UB to define any of the functions from the standard library. It is UB to dereference a pointer after it has been passed to free. It is therefore completely impossible to implement a C standard library in standard C.
As a result, compilers define a superset of C, which allows the standard library to be implemented. The -fno-builtin-* flags are intended to support this.
Some of the cases are particularly complex. For example, some of the math.h functions need to disallow the compiler from treating others as builtins. We've had cases in FreeBSD's libm, for example, where part of one function was turned by the compiler into something calling another libm function that, in turn called the first one. Specifying -fno-builtin-* flags allows the compiler to know that this transform is unsound.