LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 2461 - __attribute__ ((noreturn)) in a function parameter
Summary: __attribute__ ((noreturn)) in a function parameter
Status: RESOLVED FIXED
Alias: None
Product: clang
Classification: Unclassified
Component: Frontend (show other bugs)
Version: unspecified
Hardware: PC All
: P normal
Assignee: Unassigned Clang Bugs
URL:
Keywords:
: 5402 (view as bug list)
Depends on:
Blocks:
 
Reported: 2008-06-14 12:41 PDT by Filipe Cabecinhas
Modified: 2010-03-12 00:57 PST (History)
10 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Filipe Cabecinhas 2008-06-14 12:41:08 PDT
clang doesn't allow __attribute__ ((noreturn)) in a function parameter:
[filcab@farnsworth ~] $ cat b.c
extern void LibVEX_Init (
   /* failure exit function */
   __attribute__ ((noreturn))
   void (*failure_exit) ( void )
);
[filcab@farnsworth ~] $ ccc -o b.o -c b.c
clang -emit-llvm-bc -x c -o b.o b.c
b.c:3:20: warning: 'noreturn' attribute only applies to function types
   __attribute__ ((noreturn))
                   ^
1 diagnostic generated.
[filcab@farnsworth ~] $ gcc -o b.o -c b.c
[filcab@farnsworth ~] $
Comment 1 Eli Friedman 2008-06-14 18:02:58 PDT
Hmm, so it appears gcc allows applying the noreturn attribute to function pointers.  This is going to be a bit complicated... clang currently doesn't support attaching function attributes to types.

A slightly more straightforward testcase:
typedef int (*a)();
typedef a b __attribute((noreturn));
Comment 2 Filipe Cabecinhas 2008-06-14 18:46:43 PDT
I tried taking a peek at the source but I didn't see any way to know if a certain parameter is a function type or not. Is there a way to do that or is it necessary to make some more deep changes to know that?

Also: Is there any information about how clang works internally (except for the *.{cpp,h))?

Comment 3 Eli Friedman 2008-06-14 22:44:23 PDT
(In reply to comment #2)
> I tried taking a peek at the source but I didn't see any way to know if a
> certain parameter is a function type or not. Is there a way to do that or is it
> necessary to make some more deep changes to know that?

I haven't checked this carefully, but I think what's happening is that by the time we try to apply the noreturn attribute, we no longer have a function, but instead a function pointer. That makes your testcase internally identical to mine.

The relevant place where clang handles declaration attributes is Sema::HandleDeclAttribute.

If you have a Decl, you can get its type by calling getType().

Unfortunately, the issue here is rather complicated, because it's really an architectural bug that function attributes are associated with the function decl rather than the function type.

> Also: Is there any information about how clang works internally (except for the
> *.{cpp,h))?

There's some limited documentation on the website (clang.llvm.org). Feel free to ask any questions, and additional documentation is always welcome.
Comment 4 Anders Carlsson 2008-06-22 12:18:31 PDT
Another (possibly related) test case is

void f(int (__attribute__((__stdcall__)) *func)());

which gives

test.c:1:12: error: function cannot return array or function type 'int ()'
void f(int (__attribute__((__stdcall__)) *func)());
           ^

Comment 5 Chris Lattner 2008-06-28 19:53:04 PDT
I just completed a round of significant cleanups to attribute processing stuff.  Implementing this now should be pretty easy (just change these "function attributes" to be type attributes).  However, the hard part is that we have no place to store these.  They really should go on the function type, but those are uniqued and it is unclear how these affect type compatibility.
Comment 6 Chris Lattner 2008-06-28 19:53:48 PDT
One other way to handle this is as a form of type qualifier like CVR or address spaces.
Comment 7 Eli Friedman 2008-06-29 00:04:25 PDT
(In reply to comment #5)
> They really should go on the function type, but those
> are uniqued and it is unclear how these affect type compatibility.

Yeah, that's kind of tricky... I'd suggest that for attributes like noreturn, which don't affect the calling convention, function types with and without the attribute should be compatible, and for attributes that affect the ABI (like stdcall), the function types should be incompatible.  (This isn't really typesafe, but C fundamentally isn't typesafe in this respect anyway.)

Here's an interesting question (although I suppose it's only partly on-topic): suppose you have a pointer to a function returning a function pointer, and this declaration is decorated with __attribute((noreturn)).  Which function is affected?  And where would you place the attribute specifier to affect the other function?
Comment 8 Anders Johnsen 2009-05-16 16:59:27 PDT
This appears to be fixed in trunk.
Comment 9 Eli Friedman 2009-05-16 17:10:59 PDT
I wouldn't really call it fixed; we're simply ignoring it now.
Comment 10 Török Edwin 2009-09-05 02:14:06 PDT
(In reply to comment #9)
> I wouldn't really call it fixed; we're simply ignoring it now.
> 

It is not fixed, compilation fails with this error now:
priv/main/vex_util.c:221:1: error: function declared 'noreturn' should not return [-Winvalid-noreturn]

Since clang doesn't know that noreturn applies to function pointers, it doesn't know that vex_failure_exit is noreturn, and thinks it may return.


Comment 11 Nuno Lopes 2009-11-05 16:41:57 PST
*** Bug 5402 has been marked as a duplicate of this bug. ***
Comment 12 Nuno Lopes 2009-11-05 16:44:49 PST
*** Bug 5280 has been marked as a duplicate of this bug. ***
Comment 13 Nuno Lopes 2009-11-21 16:37:03 PST
*** Bug 5578 has been marked as a duplicate of this bug. ***
Comment 14 Charles Davis 2009-12-09 20:36:35 PST
I noticed something interesting about clang's behavior in this case. If when you declare the function pointer, you put the noreturn attribute at the beginning of the declaration, clang warns:

$ cat t.c
__attribute__((noreturn)) void f(__attribute__((noreturn)) void (*x)(void))
{
    x();
}

$ clang -c t.c
t.c:6:1: warning: function declared 'noreturn' should not return
      [-Winvalid-noreturn]
}
^
1 diagnostic generated.
$

But when you put it at the end of the declaration, it doesn't warn:

$ cat t.c
__attribute__((noreturn)) void f(void (*x)(void) __attribute__((noreturn)))
{
    x();
}

$ clang -c t.c
$

Correct me if I'm wrong, but I think that the noreturn is getting applied to the return type of the function pointer in the first case, instead of the function pointer itself. In the second case, clang is correctly applying noreturn to the function pointer type.
Comment 15 Charles Davis 2009-12-09 22:45:32 PST
(In reply to comment #14)
> Correct me if I'm wrong, but I think that the noreturn is getting applied to
> the return type of the function pointer in the first case, instead of the
> function pointer itself.
Or, the attribute for some strange reason is being silently ignored. It just occurred to me that if clang really did try to apply noreturn to the void type, it would have printed a warning to the effect of the attribute only applying to function types.

Now the question is: why is the attribute ignored when it's at the beginning of the decl but applied when it's at the end?
Comment 16 Charles Davis 2009-12-10 20:43:29 PST
(In reply to comment #15)
> (In reply to comment #14)
> > Correct me if I'm wrong, but I think that the noreturn is getting applied to
> > the return type of the function pointer in the first case, instead of the
> > function pointer itself.
> Or, the attribute for some strange reason is being silently ignored. It just
> occurred to me that if clang really did try to apply noreturn to the void type,
> it would have printed a warning to the effect of the attribute only applying to
> function types.
No, I was right the first time. I took a look at SemaType.cpp and found that, when it encounters a noreturn applied to a non-function type, it just returns *without issuing a warning*. It just happens to work with functions because we still attach the attribute to the function decl.

Now the question becomes: why is clang trying to apply the noreturn attribute to the return type instead of to the function (pointer) type?

Comment 17 Charles Davis 2009-12-13 17:59:56 PST
OK, I think I've got this figured out. The reason clang tries to apply the attribute to the return type is simply because it hasn't seen the rest of the function pointer yet. So, I've written a patch that lets clang apply noreturn to function pointer decls, and adds support for this to Sema::CheckFallThrough. It works for my simple testcase, so it should work for you. I'm going to send it to cfe-commits shortly.
Comment 18 Amine Khaldi 2009-12-15 11:18:14 PST
(In reply to comment #17)
> OK, I think I've got this figured out. The reason clang tries to apply the
> attribute to the return type is simply because it hasn't seen the rest of the
> function pointer yet. So, I've written a patch that lets clang apply noreturn
> to function pointer decls, and adds support for this to Sema::CheckFallThrough.
> It works for my simple testcase, so it should work for you. I'm going to send
> it to cfe-commits shortly.
> 

Thank you Charles. I hope you can take a look at the other affected attributes (mainly stdcall) please ?
Comment 19 Charles Davis 2009-12-15 11:41:59 PST
(In reply to comment #18)
> Thank you Charles.
You're welcome.
> I hope you can take a look at the other affected attributes
> (mainly stdcall) please ?
> 
Where do you think I'm headed next?

The whole reason I'm even on the CC list for this bug was that my original bug (which related to stdcall) got resolved as a dupe of this one. I'm thinking about reopening it. It's similar, but it's not quite the same as this bug.

I take it you're trying to compile Wine, too? (I saw your patch on wine-patches, so I know you're involved with them. Good to see a fellow Wine dev.) That's what got me interested in all this.

Anyway, my patch got committed (with test pending), so now I'm going to resolve this bug.
Comment 20 Amine Khaldi 2009-12-15 12:00:19 PST
(In reply to comment #19)
> (In reply to comment #18)
> > Thank you Charles.
> You're welcome.
> > I hope you can take a look at the other affected attributes
> > (mainly stdcall) please ?
> > 
> Where do you think I'm headed next?
> 
> The whole reason I'm even on the CC list for this bug was that my original bug
> (which related to stdcall) got resolved as a dupe of this one. I'm thinking
> about reopening it. It's similar, but it's not quite the same as this bug.

Exactly, as I tried your patch as soon as I saw it, and tried compiling the stdcall testcase, but got the warning nevertheless.

> I take it you're trying to compile Wine, too? (I saw your patch on
> wine-patches, so I know you're involved with them. Good to see a fellow Wine
> dev.) That's what got me interested in all this.

Yeah, more is coming hopefully.

> 
> Anyway, my patch got committed (with test pending), so now I'm going to resolve
> this bug.

Okay. I've CCed myself into that duplicate (didn't check the dups before).
Comment 21 Chris Lattner 2009-12-15 12:14:31 PST
Thank you for your work in this area guys!  Feel free to reopen the dupe if it isn't fixed.