//===---------------------------------------------------------------------===// // Random Notes //===---------------------------------------------------------------------===// //===---------------------------------------------------------------------===// Extensions: * "#define_target X Y" This preprocessor directive works exactly the same was as #define, but it notes that 'X' is a target-specific preprocessor directive. When used, a diagnostic is emitted indicating that the translation unit is non-portable. If a target-define is #undef'd before use, no diagnostic is emitted. If 'X' were previously a normal #define macro, the macro is tainted. If 'X' is subsequently #defined as a non-target-specific define, the taint bit is cleared. * "#define_other_target X" The preprocessor directive takes a single identifier argument. It notes that this identifier is a target-specific #define for some target other than the current one. Use of this identifier will result in a diagnostic. If 'X' is later #undef'd or #define'd, the taint bit is cleared. If 'X' is already defined, X is marked as a target-specific define. //===---------------------------------------------------------------------===// To time GCC preprocessing speed without output, use: "time gcc -MM file" This is similar to -Eonly. //===---------------------------------------------------------------------===// Interesting fact: clang -Eonly INPUTS/carbon-header-C-E.c is much faster than: wc -w INPUTS/carbon-header-C-E.c !! //===---------------------------------------------------------------------===// The 'portability' model in clang is sufficient to catch translation units (or their parts) that are not portable, but it doesn't help if the system headers are non-portable and not fixed. An alternative model that would be easy to use is a 'tainting' scheme. Consider: int32_t OSHostByteOrder(void) { #if defined(__LITTLE_ENDIAN__) return OSLittleEndian; #elif defined(__BIG_ENDIAN__) return OSBigEndian; #else return OSUnknownByteOrder; #endif } It would be trivial to mark 'OSHostByteOrder' as being non-portable (tainted) instead of marking the entire translation unit. Then, if OSHostByteOrder is never called/used by the current translation unit, the t-u wouldn't be marked non-portable. However, there is no good way to handle stuff like: extern int X, Y; #ifndef __POWERPC__ #define X Y #endif int bar() { return X; } When compiling for powerpc, the #define is skipped, so it doesn't know that bar uses a #define that is set on some other target. In practice, limited cases could be handled by scanning the skipped region of a #if, but the fully general case cannot be implemented efficiently. In this case, for example, the #define in the protected region could be turned into either a #define_target or #define_other_target as appropriate. The harder case is code like this (from OSByteOrder.h): #if (defined(__ppc__) || defined(__ppc64__)) #include #elif (defined(__i386__) || defined(__x86_64__)) #include #else #include #endif The realistic way to fix this is by having an initial #ifdef __llvm__ that defines its contents in terms of the llvm bswap intrinsics. Other things should be handled on a case-by-case basis. We probably have to do something smarter like this in the future. The C++ header contains a lot of code like this: static const int digits10 = __LDBL_DIG__; static const int min_exponent = __LDBL_MIN_EXP__; static const int min_exponent10 = __LDBL_MIN_10_EXP__; static const float_denorm_style has_denorm = bool(__LDBL_DENORM_MIN__) ? denorm_present : denorm_absent; ... since this isn't being used in an #ifdef, it should be easy enough to taint the decl for these ivars. /usr/include/sys/cdefs.h contains stuff like this: #if defined(__ppc__) # if defined(__LDBL_MANT_DIG__) && defined(__DBL_MANT_DIG__) && \ __LDBL_MANT_DIG__ > __DBL_MANT_DIG__ # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 < 1040 # define __DARWIN_LDBL_COMPAT(x) __asm("_" __STRING(x) "$LDBLStub") # else # define __DARWIN_LDBL_COMPAT(x) __asm("_" __STRING(x) "$LDBL128") # endif # define __DARWIN_LDBL_COMPAT2(x) __asm("_" __STRING(x) "$LDBL128") # define __DARWIN_LONG_DOUBLE_IS_DOUBLE 0 # else # define __DARWIN_LDBL_COMPAT(x) /* nothing */ # define __DARWIN_LDBL_COMPAT2(x) /* nothing */ # define __DARWIN_LONG_DOUBLE_IS_DOUBLE 1 # endif #elif defined(__i386__) || defined(__ppc64__) || defined(__x86_64__) # define __DARWIN_LDBL_COMPAT(x) /* nothing */ # define __DARWIN_LDBL_COMPAT2(x) /* nothing */ # define __DARWIN_LONG_DOUBLE_IS_DOUBLE 0 #else # error Unknown architecture #endif An ideal way to solve this issue is to mark __DARWIN_LDBL_COMPAT / __DARWIN_LDBL_COMPAT2 / __DARWIN_LONG_DOUBLE_IS_DOUBLE as being non-portable because they depend on non-portable macros. In practice though, this may end up being a serious problem: every use of printf will mark the translation unit non-portable if targetting ppc32 and something else. //===---------------------------------------------------------------------===//