Random small issues

I tried compiling Dovecot using clang. The blocker problem was that
va_arg() isn't implemented. Other than that there are a few other small
issues:

1. automake's dependency tracking doesn't work with ccc for some reason.
It always recompiles everything. I didn't bother trying to figure out
why.

2. Some small differences with ccc/clang and gcc cause warnings and
compiler errors:

// gcc thinks these types are compatible, clang doesn't
struct foo {
  int x;
};

int main(void) {
  const struct foo *src;

  if (!__builtin_types_compatible_p(struct foo, typeof(*src)))
    printf("error\n");
  return 0;
}

// noreturn attribute is useful also for function pointers, but
// clang gives a warning
static void (*fatal)(void) __attribute__((noreturn));

static void __attribute__((noreturn))
die(void)
{
  fatal();
}

int main(void) {
  fatal();
  return 0;
}

// clang gives a warning, gcc doesn't. I guess gcc figures out that
// a format argument is going in so it should also be coming out.
// That's how I also prefer it (unless there's another way to
// prevent the warning?)
static const char * __attribute__((format_arg(1)))
printf_format_fix(const char *format)
{
  // maybe modify format
  return format;
}

int main(void) {
  printf(printf_format_fix("%s"), "hello");
  return 0;
}

Thanks for the reports Timo!

I tried compiling Dovecot using clang. The blocker problem was that
va_arg() isn’t implemented. Other than that there are a few other small
issues:

va_arg of structures, I presume? va_arg should sort of work for other things.

  1. automake’s dependency tracking doesn’t work with ccc for some reason.
    It always recompiles everything. I didn’t bother trying to figure out
    why.

I’m not sure what “automake’s dependency tracking” translates to. clang/ccc doesn’t support -MM and friends yet, http://llvm.org/PR2618, which could very well be the problem.

  1. Some small differences with ccc/clang and gcc cause warnings and
    compiler errors:

// gcc thinks these types are compatible, clang doesn’t
struct foo {
int x;
};

int main(void) {
const struct foo *src;

if (!__builtin_types_compatible_p(struct foo, typeof(*src)))
printf(“error\n”);
return 0;
}

Filed for discussion here: http://llvm.org/PR2919

// noreturn attribute is useful also for function pointers, but
// clang gives a warning
static void (*fatal)(void) attribute((noreturn));

static void attribute((noreturn))
die(void)
{
fatal();
}

int main(void) {
fatal();
return 0;
}

Fixed here: http://llvm.org/viewvc/llvm-project?view=rev&revision=57778, confirmation appreciated.

// clang gives a warning, gcc doesn’t. I guess gcc figures out that
// a format argument is going in so it should also be coming out.
// That’s how I also prefer it (unless there’s another way to
// prevent the warning?)
static const char * attribute((format_arg(1)))
printf_format_fix(const char *format)
{
// maybe modify format
return format;
}

int main(void) {
printf(printf_format_fix(“%s”), “hello”);
return 0;
}

Honestly I’m not sure what is going on here. Note that by default clang applies more stringent default warnings than (my) gcc, however I do see gcc as not warning on this code. Feel free to file a bug on this, but I’m not really sure what the desired behavior is.

  • Daniel

Thanks for the reports Timo!

        I tried compiling Dovecot using clang. The blocker problem was
        that
        va_arg() isn't implemented. Other than that there are a few
        other small
        issues:

va_arg of structures, I presume? va_arg should sort of work for other
things.

No. Looks like this is again a difference between OS X and Debian. This
assert-crashes llc on Debian:

#include <stdarg.h>
void foo(const char *fmt, va_list va) {
  va_arg(va, int);
}
int main(int argc, char *argv) { return 0; }

llc: X86ISelLowering.cpp:5453: llvm::SDValue
llvm::X86TargetLowering::LowerVAARG(llvm::SDValue, llvm::SelectionDAG&):
Assertion `0 && "VAArgInst is not yet implemented for x86-64!"' failed.

Since it's an assert which says this isn't implemented, I thought it
wasn't implemented anywhere.. If I make foo static, it works. Backtrace
shows:

#2 0x00007f1b31110dc9 in __assert_fail () from /lib/libc.so.6
#3 0x0000000000bbc9b2 in llvm::X86TargetLowering::LowerVAARG
(this=0x15cde78,
    Op={Node = 0x15e1068, ResNo = 0}, DAG=@0x15e0450)
    at X86ISelLowering.cpp:5453
#4 0x0000000000be5ac1 in llvm::X86TargetLowering::LowerOperation (
    this=0x15cde78, Op={Node = 0x15e1068, ResNo = 0}, DAG=@0x15e0450)
    at X86ISelLowering.cpp:6134
#5 0x0000000000d40f4d in LegalizeOp (this=0x7fff3a217f70, Op=
      {Node = 0x15e1068, ResNo = 0}) at LegalizeDAG.cpp:3296
#6 0x0000000000d60cb4 in HandleOp (this=0x7fff3a217f70, Op=
      {Node = 0x15e1068, ResNo = 0}) at LegalizeDAG.cpp:412
#7 0x0000000000d60ebd in LegalizeDAG (this=0x7fff3a217f70)
    at LegalizeDAG.cpp:291
#8 0x0000000000d60fdf in llvm::SelectionDAG::Legalize (this=0x15e0450)
    at LegalizeDAG.cpp:7415
#9 0x0000000000d0553d in llvm::SelectionDAGISel::CodeGenAndEmitDAG (
    this=0x15df5f0) at SelectionDAGISel.cpp:598
#10 0x0000000000d079ba in llvm::SelectionDAGISel::SelectBasicBlock (
    this=0x15df5f0, LLVMBB=0x15cb0f0, Begin=
      {<bidirectional_iterator<llvm::Instruction, long int>> =
{<std::iterator<std::bidirectional_iterator_tag, llvm::Instruction, long
int, llvm::Instruction*, llvm::Instruction&>> = {<No data fields>}, <No
data fields>}, NodePtr = 0x15cc1e8}, End=
      {<bidirectional_iterator<llvm::Instruction, long int>> =
{<std::iterator<std::bidirectional_iterator_tag, llvm::Instruction, long
int, llvm::Instruction*, llvm::Instruction&>> = {<No data fields>}, <No
data fields>}, NodePtr = 0x15cc240}) at SelectionDAGISel.cpp:488
#11 0x0000000000d08331 in llvm::SelectionDAGISel::SelectAllBasicBlocks (
    this=0x15df5f0, Fn=@0x15cbfc0, MF=@0x15f75f0, MMI=0x15ef730,
    TII=@0x15cdd58) at SelectionDAGISel.cpp:826
#12 0x0000000000d09042 in llvm::SelectionDAGISel::runOnFunction (
    this=0x15df5f0, Fn=@0x15cbfc0) at SelectionDAGISel.cpp:317
#13 0x0000000000f7b1fd in llvm::FPPassManager::runOnFunction
(this=0x15ccc00,
    F=@0x15cbfc0) at PassManager.cpp:1321
#14 0x0000000000f7bd40 in llvm::FunctionPassManagerImpl::run
(this=0x15cc660,
    F=@0x15cbfc0) at PassManager.cpp:1279
#15 0x0000000000f7be9e in llvm::FunctionPassManager::run
(this=0x7fff3a2186a0,
    F=@0x15cbfc0) at PassManager.cpp:1224
#16 0x0000000000801508 in main (argc=1, argv=0x7fff3a2188c8) at
llc.cpp:313

        1. automake's dependency tracking doesn't work with ccc for
        some reason.
        It always recompiles everything. I didn't bother trying to
        figure out
        why.

I'm not sure what "automake's dependency tracking" translates to.
clang/ccc doesn't support -MM and friends yet, http://llvm.org/PR2618,
which could very well be the problem.

Looks like configure doesn't detect any usable way to track dependencies
so it sets depmode=none. Maybe the -MM would help.

Fixed here:
http://llvm.org/viewvc/llvm-project?view=rev&revision=57778,
confirmation appreciated.

Works.

        // clang gives a warning, gcc doesn't. I guess gcc figures out
        that
        // a format argument is going in so it should also be coming
        out.
        // That's how I also prefer it (unless there's another way to
        // prevent the warning?)
        static const char * __attribute__((format_arg(1)))
        printf_format_fix(const char *format)
        {
               // maybe modify format
               return format;
        }
        
        int main(void) {
               printf(printf_format_fix("%s"), "hello");
               return 0;
        }

Honestly I'm not sure what is going on here. Note that by default
clang applies more stringent default warnings than (my) gcc, however I
do see gcc as not warning on this code. Feel free to file a bug on
this, but I'm not really sure what the desired behavior is.

I wouldn't mind if clang did things differently, just as long as there
was some way to avoid this warning. Like perhaps a new attribute that
said the return value was a safe format string.