For example look at the follwoing code:
------------------------------------------------------
#include <stdlib.h>
int error(int errno, int fatal)
{
/* print error */
if (fatal)
exit(1);
return 0;
}
void foo(void) __attribute__ ((__noreturn__));
void foo(void)
{
/* do something */
error(1, 1);
}
------------------------------------------------------
If I compile this with gcc I get a warning
$ cc -Wall -O6 -S foo.c
foo.c: In function `foo':
foo.c:18: warning: `noreturn' function does return
This happens, alhough error() is inlined into foo(), the if condition
evaluation and return statement are optimized away and the compiler
obviously did see, that foo() cannot return and also optimized away
the return from foo(). This look as follows:
.file "foo.c"
.text
.p2align 4,,15
.globl error
.type error, @function
error:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 12(%ebp), %eax
testl %eax, %eax
jne .L4
leave
xorl %eax, %eax
ret
.L4:
movl $1, (%esp)
call exit
.size error, .-error
.p2align 4,,15
.globl foo
.type foo, @function
foo:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $1, (%esp)
call exit
.size foo, .-foo
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.4.6"
As you can see, foo() ends with the call to exit and gcc did actually
see that this call cannot return. Is there a way to eliminate the
warning about foo() returning?
BTW, gcc-4.2.2 still produces the same warning.
urs
This is what happens "afterwards".
From the source, the noreturn "does not stand" if you do not do an in depth
analysis. noreturn is a strong attribute. It modifies the generated code in a
way that the function never ever should return. If there is slightest doubt in
this, the compiler is right in warning you.
The noreturn schould be on a funktion that really does "not return". No fancy
conditionals, no tricks involved.
You should reshuffle this code a little bit:
int error(int errno)
{
/* print */
}
void fatal(int errno) __attribute__((__noreturn__))
{
error(errno);
exit(1);
}
void foo()
{
/* do something */
fatal(1);
}
For backward compatibility till you changed all callsites you can do:
int real_error(int errno)
{
/* print */
}
void fatal(int errno) __attribute__((__noreturn__))
{
real_error(errno);
exit(1);
}
int error(int errno, int fatal)
{
if(fatal)
fatal(errno);
else
real_error(errno);
}
now you have a little time to schedule a whole sweep over the program to change
all calls "error(x, 1)" to fatal. Then you can make another sweep removing the
second argument to error and rename real_error to error.
[snip]
>
>
> urs
Greetings
Jan
--
(2) No matter how hard you push and no matter what the priority,
you can't increase the speed of light.
RFC 1925
AFAIK the warning is a front-end thing and pays no attention to
inlining and dead code elimination.
> As you can see, foo() ends with the call to exit and gcc did actually
> see that this call cannot return. Is there a way to eliminate the
> warning about foo() returning?
You'll have to fix the code, I think. I'd just add a call to exit()
in foo.
But why do you care about the warning, anyway? It's harmless. gcc
warns about all manner of things, not all of which are errors. It's
just a message to the programmer to say "You might want to look at
this."
Andrew.
Or put the extra exit() in a 'noreturn' fatal() function, and call
that instead of error(whatever, 1) from foo():
void fatal(int e) __attribute__ ((__noreturn__));
void fatal(int e)
{
error(e, 1);
exit(1);
}
--
Hallvard