Invalid noreturn

Hi.

I was trying to compile git with clang but it yielded the "function declared 'noreturn' should not return" error. Here is a small test case:

[filcab@Farnsworth ~] $ cat a.c
#include <stdio.h>
#include <stdlib.h>

#define NORETURN __attribute__((__noreturn__))
extern void a(void);

static NORETURN void die_builtin(int err)
{
         exit(128);
}

static NORETURN void (*die_routine)(int i) = die_builtin;

extern NORETURN void die(int err);
void die (int err)
{
   die_routine(err);
   a();
}

extern NORETURN void aaa(int err);
void aaa(int err)
{
   exit(1);
   a();
}

[filcab@Farnsworth ~] $ clang -c a.c
a.c:20:1: warning: function declared 'noreturn' should not return
       [-Winvalid-noreturn]
}
^
1 diagnostic generated.
[filcab@Farnsworth ~] $

Is this supposed to be like this? Or is it a bug? If I call a noreturn function pointer, I get the warning. If I call exit(), I don't.
I was expecting both to have the same behaviour.

The code where I saw this had a die() function which received a va_list. After calling this die() function, they "called" the macro va_close() and this triggered the warning.

Regards,

   F

Filipe Cabecinhas wrote:

Hi.

I was trying to compile git with clang but it yielded the "function
declared 'noreturn' should not return" error. Here is a small test case:

[filcab@Farnsworth ~] $ cat a.c
#include <stdio.h>
#include <stdlib.h>

#define NORETURN __attribute__((__noreturn__))
extern void a(void);

static NORETURN void die_builtin(int err)
{
         exit(128);
}

static NORETURN void (*die_routine)(int i) = die_builtin;

extern NORETURN void die(int err);
void die (int err)
{
   die_routine(err);
   a();
}

extern NORETURN void aaa(int err);
void aaa(int err)
{
   exit(1);
   a();
}

[filcab@Farnsworth ~] $ clang -c a.c
a.c:20:1: warning: function declared 'noreturn' should not return
       [-Winvalid-noreturn]
}
^
1 diagnostic generated.
[filcab@Farnsworth ~] $

Is this supposed to be like this? Or is it a bug? If I call a noreturn
function pointer, I get the warning. If I call exit(), I don't.
I was expecting both to have the same behaviour.

The code where I saw this had a die() function which received a va_list.
After calling this die() function, they "called" the macro va_close()
and this triggered the warning.

I thought I fixed this!

It seems to be related to what happens after the call to the noreturn
function pointer. If there's nothing after it, it doesn't warn, but if
there's something after it, it does warn.

Here's another useful and interesting tidbit: if you put the noreturn
attribute inside the parentheses with the function name, or after the
parameter list, the problem goes away:

static void (NORETURN *die_routine)(int i); /* this works */
static void (*die_routine)(int i) NORETURN; /* so does this */
static NORETURN void (*die_routine)(int i); /* but not this */
static void NORETURN (*die_routine)(int i); /* and not this */

The reason is that, when clang sees the noreturn in the second two
cases, it hasn't yet seen the whole function header yet, so it tries (in
vain) to apply it to the return type. What we really want is for clang
to try to apply it to the function type, not the type it returns. I need
to figure this out anyway, so calling convention attributes work
properly in my future patches.

Chip