diff mbox

Modify gcc for use with gdb (issue5132047)

Message ID 20110926220500.9254022266A@jade.mtv.corp.google.com
State New
Headers show

Commit Message

Lawrence Crowl Sept. 26, 2011, 10:05 p.m. UTC
The gcc source uses several constructs that GDB does not understand.
This patch corrects some of them.  It affects only compilers built
with ENABLE_TREE_CHECKING, and hence release compilers are unaffected.

In particular, I change the implementation of CHECK macros using
__extension__ into macros calling inline functions.  I do not change
the accessor macros themselves.

The effect is that it now possible to get useful responses to gdb
command like

    (gdb) print DECL_FUNCTION_CODE (decl)

To make the feature work, you must define two macros within gdb.

    (gdb) macro define __FILE__ "gdb"
    (gdb) macro define __LINE__ 1

The reason for these definitions is that gdb does not expand the magic
preprocessor macros, and then cannot find what it thinks is a regular
symbol.  (There is now a gdb issue for this problem.)  I added these
definitions to gdbinit.in.

There a non-transparent change in behavior that may affect some users.
The inline functions will introduce additional lines in a sequence of
gdb 'step' commands.  Use 'next' instead.

There is one change that appears to be completely transparent, but
I mention it here for completeness.  The static type of the result
of the macros is 'tree' rather than a more specific sub-type of
tree.  The reason for this change is that gdb does not parse typeof
expressions.  (There is now a gdb issue for this problem.)

Three run average bootstrap times with all default languages enabled
are 10234.1 second base and 10272.7 seconds with patch for a 0.377%
slow down.

Tested on x86-64.



--
This patch is available for review at http://codereview.appspot.com/5132047

Comments

Paolo Carlini Sept. 26, 2011, 11:14 p.m. UTC | #1
On 09/27/2011 12:05 AM, crowl@google.com wrote:
> The gcc source uses several constructs that GDB does not understand.
> This patch corrects some of them.  It affects only compilers built
> with ENABLE_TREE_CHECKING, and hence release compilers are unaffected.
This is "funny". I have been using for years and years the attached 
.gdbinit, assuming it was part of life ;) (I don't know much about gdb, 
it's clear)

Paolo.
# Redefine any macro from tree.h that uses a statement expression.
# Last in case of failure.
macro define TREE_CHECK(T, CODE) (T)
macro define TREE_NOT_CHECK(T, CODE) (T)
macro define TREE_CHECK2(T, CODE1, CODE2) (T)
macro define TREE_NOT_CHECK2(T, CODE1, CODE2) (T)
macro define TREE_CHECK3(T, CODE1, CODE2, CODE3) (T)
macro define TREE_NOT_CHECK3(T, CODE1, CODE2, CODE3) (T)
macro define TREE_CHECK4(T, CODE1, CODE2, CODE3, CODE4) (T)
macro define NON_TREE_CHECK4(T, CODE1, CODE2, CODE3, CODE4) (T)
macro define TREE_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) (T)
macro define TREE_NOT_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) (T)
macro define CONTAINS_STRUCT_CHECK(T, STRUCT) (T)
macro define TREE_CLASS_CHECK(T, CLASS) (T)
macro define TREE_RANGE_CHECK(T, CODE1, CODE2) (T)
macro define OMP_CLAUSE_SUBCODE_CHECK(T, CODE) (T)
macro define OMP_CLAUSE_RANGE_CHECK(T, CODE1, CODE2) (T)
macro define EXPR_CHECK(T) (T)
macro define GIMPLE_STMT_CHECK(T) (T)
macro define NON_TYPE_CHECK(T) (T)
macro define TREE_VEC_ELT_CHECK(T, I) ((T)->vec.a[I])
macro define PHI_NODE_ELT_CHECK(T, I) ((T)->phi.a[I])
macro define OMP_CLAUSE_ELT_CHECK(T, I) ((T)->omp_clause.ops[I])
macro define TREE_OPERAND_CHECK(T, I) ((T)->exp.operands[I])
macro define TREE_OPERAND_CHECK_CODE(T, CODE, I) ((T)->exp.operands[I])
macro define GIMPLE_STMT_OPERAND_CHECK(T, I) ((T)->gstmt.operands[I])
macro define TREE_RTL_OPERAND_CHECK(T, CODE, I) ((T)->exp.operands[I])
macro define TREE_CHAIN(NODE) ((NODE)->common.chain)
macro define TREE_TYPE(NODE) ((NODE)->common.type)
# Paolo
macro define LANG_TYPE_CLASS_CHECK(NODE) (&TYPE_LANG_SPECIFIC (NODE)->u.c)
macro define LANG_TYPE_PTRMEM_CHECK(NODE) (&TYPE_LANG_SPECIFIC (NODE)->u.ptrmem)
# Another handy one.
macro define __builtin_offsetof(T, F) ((int) &(((T *) 0)->F))
Jakub Jelinek Sept. 27, 2011, 7:14 a.m. UTC | #2
On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
> There a non-transparent change in behavior that may affect some users.
> The inline functions will introduce additional lines in a sequence of
> gdb 'step' commands.  Use 'next' instead.

That is IMHO a serious obstackle.  If anything, the inlines should
use always_inline, artificial attributes, but don't know if GDB treats them
already specially and doesn't step into them with step.
Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.

The .gdbinit macro redefinition Paolo posted sounds to be a better approach.

	Jakub
Richard Biener Sept. 27, 2011, 7:35 a.m. UTC | #3
On Tue, Sep 27, 2011 at 9:14 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
>> There a non-transparent change in behavior that may affect some users.
>> The inline functions will introduce additional lines in a sequence of
>> gdb 'step' commands.  Use 'next' instead.
>
> That is IMHO a serious obstackle.  If anything, the inlines should
> use always_inline, artificial attributes, but don't know if GDB treats them
> already specially and doesn't step into them with step.
> Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.
>
> The .gdbinit macro redefinition Paolo posted sounds to be a better approach.

Yeah, I already see me typing s<return>finish<return> gazillion of times when
trying to step into a function call that produces a function argument
... there is
already the very very very annoying tree_code_length function that you get for
each TREE_OPERAND (...) macro on function arguments.  I'd be very opposed
to any change that makes this situation worse.

Richard.

>        Jakub
>
Richard Biener Sept. 27, 2011, 7:37 a.m. UTC | #4
On Tue, Sep 27, 2011 at 9:35 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Tue, Sep 27, 2011 at 9:14 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
>>> There a non-transparent change in behavior that may affect some users.
>>> The inline functions will introduce additional lines in a sequence of
>>> gdb 'step' commands.  Use 'next' instead.
>>
>> That is IMHO a serious obstackle.  If anything, the inlines should
>> use always_inline, artificial attributes, but don't know if GDB treats them
>> already specially and doesn't step into them with step.
>> Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.
>>
>> The .gdbinit macro redefinition Paolo posted sounds to be a better approach.
>
> Yeah, I already see me typing s<return>finish<return> gazillion of times when
> trying to step into a function call that produces a function argument
> ... there is
> already the very very very annoying tree_code_length function that you get for
> each TREE_OPERAND (...) macro on function arguments.  I'd be very opposed
> to any change that makes this situation worse.

tree_operand_length actually.  Please produce a patch that makes this function
transparent to gdb, then I might be convinced converting the other macros to
such function might be worthwhile.

Thanks,
Richard.

> Richard.
>
>>        Jakub
>>
>
Diego Novillo Oct. 5, 2011, 1:18 p.m. UTC | #5
On 11-09-27 03:37 , Richard Guenther wrote:
> On Tue, Sep 27, 2011 at 9:35 AM, Richard Guenther
> <richard.guenther@gmail.com>  wrote:
>> On Tue, Sep 27, 2011 at 9:14 AM, Jakub Jelinek<jakub@redhat.com>  wrote:
>>> On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
>>>> There a non-transparent change in behavior that may affect some users.
>>>> The inline functions will introduce additional lines in a sequence of
>>>> gdb 'step' commands.  Use 'next' instead.
>>>
>>> That is IMHO a serious obstackle.  If anything, the inlines should
>>> use always_inline, artificial attributes, but don't know if GDB treats them
>>> already specially and doesn't step into them with step.
>>> Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.
>>>
>>> The .gdbinit macro redefinition Paolo posted sounds to be a better approach.
>>
>> Yeah, I already see me typing s<return>finish<return>  gazillion of times when
>> trying to step into a function call that produces a function argument
>> ... there is
>> already the very very very annoying tree_code_length function that you get for
>> each TREE_OPERAND (...) macro on function arguments.  I'd be very opposed
>> to any change that makes this situation worse.
>
> tree_operand_length actually.  Please produce a patch that makes this function
> transparent to gdb, then I might be convinced converting the other macros to
> such function might be worthwhile.
>
> Thanks,
> Richard.

I think we need to find a solution for this situation.  The suggestions 
I see in this thread are nothing but workarounds to cope with current 
debugging limitations.  We have learned to live with them and hack 
around them, but debugging GCC is already a daunting task, and I think 
we can improve it.

Richard, yes, stepping into one-liner inline functions can be 
aggravating (particularly with some of the 2-3 embedded function calls 
we have in some places).  However, the ability to easily inspect state 
of data structures using the standard accessors is fundamental. 
Particularly, for developers that may not have the extensive knowledge 
of internals that you do.

Jakub, is size of a debuggable cc1/cc1plus really all that important? 
Yes, more debug info makes for bigger binaries.  But when debugging, 
that hardly matters.  Unless we were talking about a multi-Gb binary, 
which we aren't.

I would like to solve this problem for all inline functions that we may 
not care to step into.  There is a whole bunch of one-liners that 
generally annoy me: tree_operand_length, gimple_op, ... in fact, all the 
gimple accessors, etc.

How about one of these two ideas?

1- Add -g to the list of supported settings in #pragma GCC optimize (or 
create a new #pragma GCC no_debug).  This way, we can brace all these 
one liners with:

#pragma push_options
#pragma GCC optimize ("-g0")
[ ... inline functions ... ]
#pragma pop_options


2- Similar to #1, but with __attribute__ in each function declaration. 
I think I prefer #1 since it's simpler for the user to specify.


This would also let us generate smaller debug binaries, since the 
bracketed functions would not get any debug info at all.

Any reason why that scheme couldn't work?  It works well for separate TUs.


Thanks.  Diego.
Richard Biener Oct. 5, 2011, 1:45 p.m. UTC | #6
On Wed, Oct 5, 2011 at 3:18 PM, Diego Novillo <dnovillo@google.com> wrote:
> On 11-09-27 03:37 , Richard Guenther wrote:
>>
>> On Tue, Sep 27, 2011 at 9:35 AM, Richard Guenther
>> <richard.guenther@gmail.com>  wrote:
>>>
>>> On Tue, Sep 27, 2011 at 9:14 AM, Jakub Jelinek<jakub@redhat.com>  wrote:
>>>>
>>>> On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
>>>>>
>>>>> There a non-transparent change in behavior that may affect some users.
>>>>> The inline functions will introduce additional lines in a sequence of
>>>>> gdb 'step' commands.  Use 'next' instead.
>>>>
>>>> That is IMHO a serious obstackle.  If anything, the inlines should
>>>> use always_inline, artificial attributes, but don't know if GDB treats
>>>> them
>>>> already specially and doesn't step into them with step.
>>>> Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.
>>>>
>>>> The .gdbinit macro redefinition Paolo posted sounds to be a better
>>>> approach.
>>>
>>> Yeah, I already see me typing s<return>finish<return>  gazillion of times
>>> when
>>> trying to step into a function call that produces a function argument
>>> ... there is
>>> already the very very very annoying tree_code_length function that you
>>> get for
>>> each TREE_OPERAND (...) macro on function arguments.  I'd be very opposed
>>> to any change that makes this situation worse.
>>
>> tree_operand_length actually.  Please produce a patch that makes this
>> function
>> transparent to gdb, then I might be convinced converting the other macros
>> to
>> such function might be worthwhile.
>>
>> Thanks,
>> Richard.
>
> I think we need to find a solution for this situation.  The suggestions I
> see in this thread are nothing but workarounds to cope with current
> debugging limitations.  We have learned to live with them and hack around
> them, but debugging GCC is already a daunting task, and I think we can
> improve it.
>
> Richard, yes, stepping into one-liner inline functions can be aggravating
> (particularly with some of the 2-3 embedded function calls we have in some
> places).  However, the ability to easily inspect state of data structures
> using the standard accessors is fundamental. Particularly, for developers
> that may not have the extensive knowledge of internals that you do.

It is much more important to optimize my debugging time as experienced
developer resources are more scarce than some random unexperienced
guy that happens to dig into GCC.

;)

or not really ;).

> Jakub, is size of a debuggable cc1/cc1plus really all that important? Yes,
> more debug info makes for bigger binaries.  But when debugging, that hardly
> matters.  Unless we were talking about a multi-Gb binary, which we aren't.
>
> I would like to solve this problem for all inline functions that we may not
> care to step into.  There is a whole bunch of one-liners that generally
> annoy me: tree_operand_length, gimple_op, ... in fact, all the gimple
> accessors, etc.
>
> How about one of these two ideas?
>
> 1- Add -g to the list of supported settings in #pragma GCC optimize (or
> create a new #pragma GCC no_debug).  This way, we can brace all these one
> liners with:
>
> #pragma push_options
> #pragma GCC optimize ("-g0")
> [ ... inline functions ... ]
> #pragma pop_options
>
>
> 2- Similar to #1, but with __attribute__ in each function declaration. I
> think I prefer #1 since it's simpler for the user to specify.
>
>
> This would also let us generate smaller debug binaries, since the bracketed
> functions would not get any debug info at all.
>
> Any reason why that scheme couldn't work?  It works well for separate TUs.

If you crash inside those -g0 marked functions, what happens?  Why
not use the artificial attribute on them instead?  At least what is documented
is exactly what we want (well, at least it seems to me).

Thus, produce a patch that improves tree_operand_length with either
approach so we can test it.

Richard.

>
> Thanks.  Diego.
>
Diego Novillo Oct. 5, 2011, 2:10 p.m. UTC | #7
On Wed, Oct 5, 2011 at 09:45, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Wed, Oct 5, 2011 at 3:18 PM, Diego Novillo <dnovillo@google.com> wrote:
>> On 11-09-27 03:37 , Richard Guenther wrote:
>>>
>>> On Tue, Sep 27, 2011 at 9:35 AM, Richard Guenther
>>> <richard.guenther@gmail.com>  wrote:
>>>>
>>>> On Tue, Sep 27, 2011 at 9:14 AM, Jakub Jelinek<jakub@redhat.com>  wrote:
>>>>>
>>>>> On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
>>>>>>
>>>>>> There a non-transparent change in behavior that may affect some users.
>>>>>> The inline functions will introduce additional lines in a sequence of
>>>>>> gdb 'step' commands.  Use 'next' instead.
>>>>>
>>>>> That is IMHO a serious obstackle.  If anything, the inlines should
>>>>> use always_inline, artificial attributes, but don't know if GDB treats
>>>>> them
>>>>> already specially and doesn't step into them with step.
>>>>> Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.
>>>>>
>>>>> The .gdbinit macro redefinition Paolo posted sounds to be a better
>>>>> approach.
>>>>
>>>> Yeah, I already see me typing s<return>finish<return>  gazillion of times
>>>> when
>>>> trying to step into a function call that produces a function argument
>>>> ... there is
>>>> already the very very very annoying tree_code_length function that you
>>>> get for
>>>> each TREE_OPERAND (...) macro on function arguments.  I'd be very opposed
>>>> to any change that makes this situation worse.
>>>
>>> tree_operand_length actually.  Please produce a patch that makes this
>>> function
>>> transparent to gdb, then I might be convinced converting the other macros
>>> to
>>> such function might be worthwhile.
>>>
>>> Thanks,
>>> Richard.
>>
>> I think we need to find a solution for this situation.  The suggestions I
>> see in this thread are nothing but workarounds to cope with current
>> debugging limitations.  We have learned to live with them and hack around
>> them, but debugging GCC is already a daunting task, and I think we can
>> improve it.
>>
>> Richard, yes, stepping into one-liner inline functions can be aggravating
>> (particularly with some of the 2-3 embedded function calls we have in some
>> places).  However, the ability to easily inspect state of data structures
>> using the standard accessors is fundamental. Particularly, for developers
>> that may not have the extensive knowledge of internals that you do.
>
> It is much more important to optimize my debugging time as experienced
> developer resources are more scarce than some random unexperienced
> guy that happens to dig into GCC.
>
> ;)
>
> or not really ;).

You are being facetious, I hope.  Part of the reason that experienced
developers are scarce is precisely because dealing with GCC's code
base is so daunting.  We should be trying to attract those random
inexperienced developers, not scare them away.

The experienced developers will retire, eventually.  Who is going to
replace them?


>> Jakub, is size of a debuggable cc1/cc1plus really all that important? Yes,
>> more debug info makes for bigger binaries.  But when debugging, that hardly
>> matters.  Unless we were talking about a multi-Gb binary, which we aren't.
>>
>> I would like to solve this problem for all inline functions that we may not
>> care to step into.  There is a whole bunch of one-liners that generally
>> annoy me: tree_operand_length, gimple_op, ... in fact, all the gimple
>> accessors, etc.
>>
>> How about one of these two ideas?
>>
>> 1- Add -g to the list of supported settings in #pragma GCC optimize (or
>> create a new #pragma GCC no_debug).  This way, we can brace all these one
>> liners with:
>>
>> #pragma push_options
>> #pragma GCC optimize ("-g0")
>> [ ... inline functions ... ]
>> #pragma pop_options
>>
>>
>> 2- Similar to #1, but with __attribute__ in each function declaration. I
>> think I prefer #1 since it's simpler for the user to specify.
>>
>>
>> This would also let us generate smaller debug binaries, since the bracketed
>> functions would not get any debug info at all.
>>
>> Any reason why that scheme couldn't work?  It works well for separate TUs.
>
> If you crash inside those -g0 marked functions, what happens?

You don't see the body of the function, but you can go up into the
exact call site.

> Why
> not use the artificial attribute on them instead?  At least what is documented
> is exactly what we want (well, at least it seems to me).

Yes, I forgot to mention in my reply.  I tried it, but you still step
into the functions.  If this is a bug with the attribute, then it
could be fixed.

> Thus, produce a patch that improves tree_operand_length with either
> approach so we can test it.

I have a slight preference for making these functions totally opaque
to the debugger.  But may be there is a setting we can use that will
not affect step and still give us some debug info in the presence of
crashes.

Tom, Cary, Ian, any suggestions?  We are trying to figure out a
compromise for tiny inline functions that are generally a nuisance
when debugging.  The scenario is a call like this: big_function_foo
(inlined_f (x), inlined_g (y));
We want to use 's' to step inside the call to big_function_foo(), but
we don't want to step into either inlined_f() or inlined_g().

I tried __attribute__((artificial)), but that is either buggy on the
gcc side or the gdb side, because I am still getting into the inlined
function (with -g3).

I proposed extending #pragma GCC options to bracket these functions
with -g0.  This would help reduce the impact of debug info size.

Thoughts?


Thanks.  Diego.
Jakub Jelinek Oct. 5, 2011, 2:15 p.m. UTC | #8
On Wed, Oct 05, 2011 at 10:10:44AM -0400, Diego Novillo wrote:
> > Why
> > not use the artificial attribute on them instead?  At least what is documented
> > is exactly what we want (well, at least it seems to me).
> 
> Yes, I forgot to mention in my reply.  I tried it, but you still step
> into the functions.  If this is a bug with the attribute, then it
> could be fixed.

If it doesn't work, then something should be done about it in gdb.
Hiding the inlines altogether from the debugger is undesirable, it is
better if the debugger has choice what to do, still the default should
be that it ignores the artificial inlines in the backtraces as well as when
stepping through, e.g. glibc headers use artificial attribute heavily
for inlines which are of no interest to users to step through too.

	Jakub
Ian Lance Taylor Oct. 5, 2011, 2:48 p.m. UTC | #9
Diego Novillo <dnovillo@google.com> writes:

>> It is much more important to optimize my debugging time as experienced
>> developer resources are more scarce than some random unexperienced
>> guy that happens to dig into GCC.
>>
>> ;)
>>
>> or not really ;).
>
> You are being facetious, I hope.  Part of the reason that experienced
> developers are scarce is precisely because dealing with GCC's code
> base is so daunting.  We should be trying to attract those random
> inexperienced developers, not scare them away.
>
> The experienced developers will retire, eventually.  Who is going to
> replace them?

Yes.  We experienced gcc developers can adapt to the tools, and we can
modify the tools to work better.  We should not hold up code
improvements because of tool deficiencies.  We should fix both problems,
but we don't have to fix them in sequence.


> Tom, Cary, Ian, any suggestions?  We are trying to figure out a
> compromise for tiny inline functions that are generally a nuisance
> when debugging.  The scenario is a call like this: big_function_foo
> (inlined_f (x), inlined_g (y));
> We want to use 's' to step inside the call to big_function_foo(), but
> we don't want to step into either inlined_f() or inlined_g().

This is a general problem when debugging C++ programs, so any solution
to this gcc-specific issue will be of general use.  However, I don't
know of a way to make it work today without changing gdb.  There is a
lot I don't know about gdb, so it is possible that there is some
approach that will work.

Basically, gdb's relatively new support for debugging inline functions
is sometimes nice, but sometimes it just gets in the way.  I guess the
most general solution is a way to mark the inline function in the source
as uninteresting.  I don't really understand the doc for the
"artificial" function attribute, but it looks like it was intended to
serve this purpose.  So it seems to me that there is a bug in gdb:
"step" should not step into a function with the "artificial" attribute.
I agree that it does not currently work that way.  Looking at the gdb
sources, it seems to me that it currently ignores DW_AT_artificial on an
ordinary function.

Ian
Richard Biener Oct. 5, 2011, 2:51 p.m. UTC | #10
On Wed, Oct 5, 2011 at 4:10 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Wed, Oct 5, 2011 at 09:45, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> On Wed, Oct 5, 2011 at 3:18 PM, Diego Novillo <dnovillo@google.com> wrote:
>>> On 11-09-27 03:37 , Richard Guenther wrote:
>>>>
>>>> On Tue, Sep 27, 2011 at 9:35 AM, Richard Guenther
>>>> <richard.guenther@gmail.com>  wrote:
>>>>>
>>>>> On Tue, Sep 27, 2011 at 9:14 AM, Jakub Jelinek<jakub@redhat.com>  wrote:
>>>>>>
>>>>>> On Mon, Sep 26, 2011 at 03:05:00PM -0700, Lawrence Crowl wrote:
>>>>>>>
>>>>>>> There a non-transparent change in behavior that may affect some users.
>>>>>>> The inline functions will introduce additional lines in a sequence of
>>>>>>> gdb 'step' commands.  Use 'next' instead.
>>>>>>
>>>>>> That is IMHO a serious obstackle.  If anything, the inlines should
>>>>>> use always_inline, artificial attributes, but don't know if GDB treats
>>>>>> them
>>>>>> already specially and doesn't step into them with step.
>>>>>> Also, I'm afraid it will significantly grow cc1plus/cc1 debug info.
>>>>>>
>>>>>> The .gdbinit macro redefinition Paolo posted sounds to be a better
>>>>>> approach.
>>>>>
>>>>> Yeah, I already see me typing s<return>finish<return>  gazillion of times
>>>>> when
>>>>> trying to step into a function call that produces a function argument
>>>>> ... there is
>>>>> already the very very very annoying tree_code_length function that you
>>>>> get for
>>>>> each TREE_OPERAND (...) macro on function arguments.  I'd be very opposed
>>>>> to any change that makes this situation worse.
>>>>
>>>> tree_operand_length actually.  Please produce a patch that makes this
>>>> function
>>>> transparent to gdb, then I might be convinced converting the other macros
>>>> to
>>>> such function might be worthwhile.
>>>>
>>>> Thanks,
>>>> Richard.
>>>
>>> I think we need to find a solution for this situation.  The suggestions I
>>> see in this thread are nothing but workarounds to cope with current
>>> debugging limitations.  We have learned to live with them and hack around
>>> them, but debugging GCC is already a daunting task, and I think we can
>>> improve it.
>>>
>>> Richard, yes, stepping into one-liner inline functions can be aggravating
>>> (particularly with some of the 2-3 embedded function calls we have in some
>>> places).  However, the ability to easily inspect state of data structures
>>> using the standard accessors is fundamental. Particularly, for developers
>>> that may not have the extensive knowledge of internals that you do.
>>
>> It is much more important to optimize my debugging time as experienced
>> developer resources are more scarce than some random unexperienced
>> guy that happens to dig into GCC.
>>
>> ;)
>>
>> or not really ;).
>
> You are being facetious, I hope.  Part of the reason that experienced
> developers are scarce is precisely because dealing with GCC's code
> base is so daunting.  We should be trying to attract those random
> inexperienced developers, not scare them away.
>
> The experienced developers will retire, eventually.  Who is going to
> replace them?
>
>
>>> Jakub, is size of a debuggable cc1/cc1plus really all that important? Yes,
>>> more debug info makes for bigger binaries.  But when debugging, that hardly
>>> matters.  Unless we were talking about a multi-Gb binary, which we aren't.
>>>
>>> I would like to solve this problem for all inline functions that we may not
>>> care to step into.  There is a whole bunch of one-liners that generally
>>> annoy me: tree_operand_length, gimple_op, ... in fact, all the gimple
>>> accessors, etc.
>>>
>>> How about one of these two ideas?
>>>
>>> 1- Add -g to the list of supported settings in #pragma GCC optimize (or
>>> create a new #pragma GCC no_debug).  This way, we can brace all these one
>>> liners with:
>>>
>>> #pragma push_options
>>> #pragma GCC optimize ("-g0")
>>> [ ... inline functions ... ]
>>> #pragma pop_options
>>>
>>>
>>> 2- Similar to #1, but with __attribute__ in each function declaration. I
>>> think I prefer #1 since it's simpler for the user to specify.
>>>
>>>
>>> This would also let us generate smaller debug binaries, since the bracketed
>>> functions would not get any debug info at all.
>>>
>>> Any reason why that scheme couldn't work?  It works well for separate TUs.
>>
>> If you crash inside those -g0 marked functions, what happens?
>
> You don't see the body of the function, but you can go up into the
> exact call site.
>
>> Why
>> not use the artificial attribute on them instead?  At least what is documented
>> is exactly what we want (well, at least it seems to me).
>
> Yes, I forgot to mention in my reply.  I tried it, but you still step
> into the functions.  If this is a bug with the attribute, then it
> could be fixed.

Did you also mark the function with always_inline?  That's a requirement
as artificial only works for inlined function bodies.

>> Thus, produce a patch that improves tree_operand_length with either
>> approach so we can test it.
>
> I have a slight preference for making these functions totally opaque
> to the debugger.  But may be there is a setting we can use that will
> not affect step and still give us some debug info in the presence of
> crashes.
>
> Tom, Cary, Ian, any suggestions?  We are trying to figure out a
> compromise for tiny inline functions that are generally a nuisance
> when debugging.  The scenario is a call like this: big_function_foo
> (inlined_f (x), inlined_g (y));
> We want to use 's' to step inside the call to big_function_foo(), but
> we don't want to step into either inlined_f() or inlined_g().
>
> I tried __attribute__((artificial)), but that is either buggy on the
> gcc side or the gdb side, because I am still getting into the inlined
> function (with -g3).
>
> I proposed extending #pragma GCC options to bracket these functions
> with -g0.  This would help reduce the impact of debug info size.
>
> Thoughts?
>
>
> Thanks.  Diego.
>
Tom Tromey Oct. 5, 2011, 3:27 p.m. UTC | #11
>>>>> "Diego" == Diego Novillo <dnovillo@google.com> writes:

Diego> Tom, Cary, Ian, any suggestions?  We are trying to figure out a
Diego> compromise for tiny inline functions that are generally a nuisance
Diego> when debugging.  The scenario is a call like this: big_function_foo
Diego> (inlined_f (x), inlined_g (y));
Diego> We want to use 's' to step inside the call to big_function_foo(), but
Diego> we don't want to step into either inlined_f() or inlined_g().

FWIW, I wrote the "macro define" stuff that Paolo posted back when I was
actively hacking on gcc.  I consider it to be mildly superior to the
inline approach, because it circumvents the runtime type checking --
this is a plus because it means that if I type the wrong thing to gdb it
doesn't cause cc1 to abort.  At least, this is a plus for me, since I
make mistakes like that with reasonable frequency.

Diego> I proposed extending #pragma GCC options to bracket these functions
Diego> with -g0.  This would help reduce the impact of debug info size.

I think this is fixing the wrong component: it means making a
one-size-fits-all decision in the gcc build, instead of just making the
debugger be more flexible.

If you want to pursue the inline function approach, I suggest
resurrecting this gdb patch:

    http://sourceware.org/bugzilla/show_bug.cgi?id=8287
    http://sourceware.org/ml/gdb-patches/2010-06/msg00417.html

Then you could add the appropriate blacklisting commands to gcc's
.gdbinit by default.

Tom
Diego Novillo Oct. 5, 2011, 3:28 p.m. UTC | #12
On Wed, Oct 5, 2011 at 10:51, Richard Guenther
<richard.guenther@gmail.com> wrote:

> Did you also mark the function with always_inline?  That's a requirement
> as artificial only works for inlined function bodies.

Yeah.  It doesn't quite work as I expect it to.  It steps into the
function at odd places.


Diego.
Paolo Carlini Oct. 5, 2011, 3:33 p.m. UTC | #13
On 10/05/2011 05:27 PM, Tom Tromey wrote:
> FWIW, I wrote the "macro define" stuff that Paolo posted back when I 
> was actively hacking on gcc.
Yes, thanks Tom! Actually, I suspected that, but couldn't remember where 
I actually got it from, maybe you posted it on a public discussion 
thread somewhere...

Paolo.
Diego Novillo Oct. 5, 2011, 3:42 p.m. UTC | #14
On Wed, Oct 5, 2011 at 11:27, Tom Tromey <tromey@redhat.com> wrote:

> Diego> I proposed extending #pragma GCC options to bracket these functions
> Diego> with -g0.  This would help reduce the impact of debug info size.
>
> I think this is fixing the wrong component: it means making a
> one-size-fits-all decision in the gcc build, instead of just making the
> debugger be more flexible.

That's true.

> If you want to pursue the inline function approach, I suggest
> resurrecting this gdb patch:
>
>    http://sourceware.org/bugzilla/show_bug.cgi?id=8287
>    http://sourceware.org/ml/gdb-patches/2010-06/msg00417.html
>
> Then you could add the appropriate blacklisting commands to gcc's
> .gdbinit by default.

I think this could work.  I'm not sure I like the idea of having to
specify all these blacklist commands, but I appreciate how it can make
debugging more flexible.

Is this patch stalled?  the last I see is Justin's reply to review
feedback, but no indication of whether it will be accepted.

Richi, Jakub, Lawrence, would you be OK with this approach?  IIUC,
this means we'd have to add a bunch of blacklist commands to
gcc/gdbinit.in.

This does ties us to gdb, but I don't think that's a problem.

How does this work with C++?  Do the functions need to be specified
with their mangled names?


Diego.
Jakub Jelinek Oct. 5, 2011, 3:57 p.m. UTC | #15
On Wed, Oct 05, 2011 at 11:42:51AM -0400, Diego Novillo wrote:
> Richi, Jakub, Lawrence, would you be OK with this approach?  IIUC,
> this means we'd have to add a bunch of blacklist commands to
> gcc/gdbinit.in.

I don't mind if it goes into gdb, but IMHO the blacklisting should
definitely default to blacklisting DW_AT_artificial inline functions
(and allowing to unblacklist them), because the artificial attribute
has been designed for that purpose already more than 4 years ago
and many headers use it.

	Jakub
Tom Tromey Oct. 5, 2011, 4:15 p.m. UTC | #16
>>>>> "Diego" == Diego Novillo <dnovillo@google.com> writes:

Tom>    http://sourceware.org/bugzilla/show_bug.cgi?id=8287

Diego> I think this could work.  I'm not sure I like the idea of having to
Diego> specify all these blacklist commands, but I appreciate how it can make
Diego> debugging more flexible.

Yeah, that's a drawback, since you have to remember to update .gdbinit.

Diego> Is this patch stalled?  the last I see is Justin's reply to review
Diego> feedback, but no indication of whether it will be accepted.

The thread continues in the next month:

    http://sourceware.org/ml/gdb-patches/2010-07/threads.html#00318

The patch needed some updates.  I don't know what happened.

Diego> How does this work with C++?  Do the functions need to be specified
Diego> with their mangled names?

I would hope not, but I don't remember any more.

Tom
Tom Tromey Oct. 5, 2011, 4:21 p.m. UTC | #17
>>>>> "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:

Jakub> I don't mind if it goes into gdb, but IMHO the blacklisting should
Jakub> definitely default to blacklisting DW_AT_artificial inline functions
Jakub> (and allowing to unblacklist them), because the artificial attribute
Jakub> has been designed for that purpose already more than 4 years ago
Jakub> and many headers use it.

Could you file a gdb bug report for this?

In general I'd appreciate it if folks making debug changes to gcc filed
bug reports against gdb.  I do follow the gcc list looking for things
like this, but I miss things sometimes, and this isn't really the best
way.

Tom
Diego Novillo Oct. 5, 2011, 4:53 p.m. UTC | #18
On Wed, Oct 5, 2011 at 11:28, Diego Novillo <dnovillo@google.com> wrote:
> On Wed, Oct 5, 2011 at 10:51, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>
>> Did you also mark the function with always_inline?  That's a requirement
>> as artificial only works for inlined function bodies.
>
> Yeah.  It doesn't quite work as I expect it to.  It steps into the
> function at odd places.

So, I played with this some more with this, and there seems to be some
inconsistency in how these attributes get handled.
http://sourceware.org/bugzilla/show_bug.cgi?id=13263

static inline int foo (int) __attribute__((always_inline,artificial));

static inline int foo (int x)
{
  int y  = x - 3;
  return y;
}

int bar (int y)
{
  return y == 0;
}

main ()
{
  foo (10);
  return bar (foo (3));
}

With GCC 4.7, the stand alone call foo(10) is not ignored by 'step'.
However, the embedded call bar(foo(3)) is ignored as I was expecting.


Diego.
Mike Stump Oct. 5, 2011, 6:20 p.m. UTC | #19
On Oct 5, 2011, at 6:18 AM, Diego Novillo wrote:
> I think we need to find a solution for this situation.

The solution Apple found and implemented is a __nodebug__ attribute, as can be seen in Apple's gcc.

We use it like so:

#define __always_inline__ __always_inline__, __nodebug__
#undef __always_inline__

in headers like mmintrn.h:

__STATIC_INLINE void __attribute__((__always_inline__))
/* APPLE LOCAL end radar 5618945 */
_mm_empty (void)
{
  __builtin_ia32_emms ();
}

to disappear the debug information for all the routines, so that the context is the context in which the routine is called (because the routine is always inlined).  It is implemented and works great.  Easy to use and understand.  Since we use the #define, #undef around the functions, it is mostly equivalent to #pragma, though, it does attach a little closer to the function.  You can strip #.* from the .i files, and not have it removed (which is nice).
Diego Novillo Oct. 5, 2011, 6:51 p.m. UTC | #20
On Wed, Oct 5, 2011 at 14:20, Mike Stump <mikestump@comcast.net> wrote:
> On Oct 5, 2011, at 6:18 AM, Diego Novillo wrote:
>> I think we need to find a solution for this situation.
>
> The solution Apple found and implemented is a __nodebug__ attribute, as can be seen in Apple's gcc.
>
> We use it like so:
>
> #define __always_inline__ __always_inline__, __nodebug__
> #undef __always_inline__
>
> in headers like mmintrn.h:
>
> __STATIC_INLINE void __attribute__((__always_inline__))
> /* APPLE LOCAL end radar 5618945 */
> _mm_empty (void)
> {
>  __builtin_ia32_emms ();
> }

Ah, nice.  Though, one of the things I am liking more and more about
the blacklist solution is that it (a) does not need any modifications
to the source code, and (b) it works with no-inline functions as well.

This gives total control to the developer.  I would blacklist a bunch
of functions I never care to go into, for instance.  Others may choose
to blacklist a different set.  And you can change that from debug
session to the next.

I agree with Jakub that artificial functions should be blacklisted
automatically, however.

Richi, Jakub, if the blacklist solution was implemented in GCC would
you agree with promoting these macros into inline functions?  This is
orthogonal to http://sourceware.org/bugzilla/show_bug.cgi?id=13263, of
course.


Thanks.  Diego.
Richard Biener Oct. 6, 2011, 8:56 a.m. UTC | #21
On Wed, Oct 5, 2011 at 6:53 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Wed, Oct 5, 2011 at 11:28, Diego Novillo <dnovillo@google.com> wrote:
>> On Wed, Oct 5, 2011 at 10:51, Richard Guenther
>> <richard.guenther@gmail.com> wrote:
>>
>>> Did you also mark the function with always_inline?  That's a requirement
>>> as artificial only works for inlined function bodies.
>>
>> Yeah.  It doesn't quite work as I expect it to.  It steps into the
>> function at odd places.
>
> So, I played with this some more with this, and there seems to be some
> inconsistency in how these attributes get handled.
> http://sourceware.org/bugzilla/show_bug.cgi?id=13263
>
> static inline int foo (int) __attribute__((always_inline,artificial));
>
> static inline int foo (int x)
> {
>  int y  = x - 3;
>  return y;
> }
>
> int bar (int y)
> {
>  return y == 0;
> }
>
> main ()
> {
>  foo (10);
>  return bar (foo (3));
> }
>
> With GCC 4.7, the stand alone call foo(10) is not ignored by 'step'.
> However, the embedded call bar(foo(3)) is ignored as I was expecting.

Hm, nothing is ignored for me with gcc 4.6.

>
> Diego.
>
Richard Biener Oct. 6, 2011, 8:58 a.m. UTC | #22
On Wed, Oct 5, 2011 at 8:51 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Wed, Oct 5, 2011 at 14:20, Mike Stump <mikestump@comcast.net> wrote:
>> On Oct 5, 2011, at 6:18 AM, Diego Novillo wrote:
>>> I think we need to find a solution for this situation.
>>
>> The solution Apple found and implemented is a __nodebug__ attribute, as can be seen in Apple's gcc.
>>
>> We use it like so:
>>
>> #define __always_inline__ __always_inline__, __nodebug__
>> #undef __always_inline__
>>
>> in headers like mmintrn.h:
>>
>> __STATIC_INLINE void __attribute__((__always_inline__))
>> /* APPLE LOCAL end radar 5618945 */
>> _mm_empty (void)
>> {
>>  __builtin_ia32_emms ();
>> }
>
> Ah, nice.  Though, one of the things I am liking more and more about
> the blacklist solution is that it (a) does not need any modifications
> to the source code, and (b) it works with no-inline functions as well.
>
> This gives total control to the developer.  I would blacklist a bunch
> of functions I never care to go into, for instance.  Others may choose
> to blacklist a different set.  And you can change that from debug
> session to the next.
>
> I agree with Jakub that artificial functions should be blacklisted
> automatically, however.
>
> Richi, Jakub, if the blacklist solution was implemented in GCC would
> you agree with promoting these macros into inline functions?  This is
> orthogonal to http://sourceware.org/bugzilla/show_bug.cgi?id=13263, of
> course.

I know you are on to that C++ thing and ending up returning a reference
to make it an lvalue.  Which I very much don't like (please, if you go
that route add _set functions and lower the case of the macros).

What's the other advantage of using inline functions?  The gdb
annoyance with the macros can be solved with the .gdbinit macro
defines (which might be nice to commit to SVN btw).

Richard.

>
> Thanks.  Diego.
>
Diego Novillo Oct. 6, 2011, 11:57 a.m. UTC | #23
On 11-10-06 04:58 , Richard Guenther wrote:

> I know you are on to that C++ thing and ending up returning a reference
> to make it an lvalue.  Which I very much don't like (please, if you go
> that route add _set functions and lower the case of the macros).

Not necessarily.  I'm after making the debugging experience easier 
(among other things).  Only a handful of macros were converted into 
functions in this patch, not all of them.  We may not *need* to convert 
all of them either.

> What's the other advantage of using inline functions?  The gdb
> annoyance with the macros can be solved with the .gdbinit macro
> defines (which might be nice to commit to SVN btw).

Static type checking, of course.  Ability to set breakpoints, and as 
time goes on, more inline functions will start showing up.

We already have several.  The blacklist feature would solve your 
annoyance with tree_operand_length, too.  Additionally, blacklist can 
deal with non-inline functions, which can be useful.


Diego.
Mike Stump Oct. 6, 2011, 6:46 p.m. UTC | #24
On Oct 6, 2011, at 1:58 AM, Richard Guenther wrote:
> On Wed, Oct 5, 2011 at 8:51 PM, Diego Novillo <dnovillo@google.com> wrote:
> What's the other advantage of using inline functions?  The gdb
> annoyance with the macros can be solved with the .gdbinit macro
> defines (which might be nice to commit to SVN btw).

http://old.nabble.com/-incremental--Patch%3A-FYI%3A-add-accessor-macros-to-gdbinit-td17370385.html

And yet, this still isn't in gcc.  :-(  I wonder how much programmer productivity we've lost due to it.
Jeff Law Oct. 6, 2011, 6:53 p.m. UTC | #25
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 10/06/11 12:46, Mike Stump wrote:
> On Oct 6, 2011, at 1:58 AM, Richard Guenther wrote:
>> On Wed, Oct 5, 2011 at 8:51 PM, Diego Novillo
>> <dnovillo@google.com> wrote: What's the other advantage of using
>> inline functions?  The gdb annoyance with the macros can be
>> solved with the .gdbinit macro defines (which might be nice to
>> commit to SVN btw).
> 
> http://old.nabble.com/-incremental--Patch%3A-FYI%3A-add-accessor-macros-to-gdbinit-td17370385.html
>
>  And yet, this still isn't in gcc.  :-(  I wonder how much
> programmer productivity we've lost due to it.
Presumably it hasn't been included because not all gdb's understand
those bits and we typically don't build with -g3.

Personally, the accessors I use are muscle-memory...  Which works
great until someone buries everything a level deeper :(

jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJOjfkaAAoJEBRtltQi2kC7nz0H/iOeU6/iqNBfMDGUMaJbFe/R
rbBFKJzAR6IOXWBJzlnA+d1qvpF5z1GsdfkqtaLImKrAFNsbv1LV58X3lc7l8yLQ
TGgLVuZPc/cJ8q0fyAd1rDBGsxRrapm5cPgyMFhl9eY1pC9pejAcbqLnXxRmIs41
NyohojHLu09o+WRkjNg79TOyapFNnY8w0Hz6PuFOyYv/eYthZ5dw9+N1XyUKey/M
6GHAOqTD3iQKz9QsG5dc+SVfTPLkToOnAZ5y8TnupFay9aLRXUlXDpFHZbre9h5C
ICK8FnWf74Xemw79ID94WWwomdND69myTf7bMlD4pFiHK3Wz6fPeR1GIdTixi7s=
=BrUJ
-----END PGP SIGNATURE-----
Mike Stump Oct. 6, 2011, 7:31 p.m. UTC | #26
On Oct 6, 2011, at 11:53 AM, Jeff Law wrote:
> Presumably it hasn't been included because not all gdb's understand
> those bits and we typically don't build with -g3.

> Personally, the accessors I use are muscle-memory...  Which works
> great until someone buries everything a level deeper :(

Yeah, which works great for encouraging new comers that doing anything with gcc is hard.  They, by definition, don't have the muscle memory, and the documentation that describes which memory their muscles should have is hard to find, or non-existant.  I'd merely favor any approach to make their life easier, -g3, a gdb macro package, all inline functions, no macros...
Tom Tromey Oct. 7, 2011, 1:42 p.m. UTC | #27
>>>>> "Jeff" == Jeff Law <law@redhat.com> writes:

Jeff> Presumably it hasn't been included because not all gdb's understand
Jeff> those bits and we typically don't build with -g3.

GCC is pretty much the perfect candidate for a -g3 build.  All those
macros...

The needed gdb changes have been in since right around when I added that
patch to the incremental branch.  Anybody with a > 3 year old gdb should
upgrade :-)

Tom
Jakub Jelinek Oct. 7, 2011, 1:45 p.m. UTC | #28
On Fri, Oct 07, 2011 at 07:42:44AM -0600, Tom Tromey wrote:
> >>>>> "Jeff" == Jeff Law <law@redhat.com> writes:
> 
> Jeff> Presumably it hasn't been included because not all gdb's understand
> Jeff> those bits and we typically don't build with -g3.
> 
> GCC is pretty much the perfect candidate for a -g3 build.  All those
> macros...
> 
> The needed gdb changes have been in since right around when I added that
> patch to the incremental branch.  Anybody with a > 3 year old gdb should
> upgrade :-)

A > 3 years old gdb is useless for debugging gcc anyway, it won't understand
epilogue unwind info, discriminators, lots of .debug_info stuff added
in the last few years and not even the .debug_macro format.

	Jakub
Jeff Law Oct. 7, 2011, 3:45 p.m. UTC | #29
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 10/07/11 07:42, Tom Tromey wrote:
>>>>>> "Jeff" == Jeff Law <law@redhat.com> writes:
> 
> Jeff> Presumably it hasn't been included because not all gdb's 
> understand Jeff> those bits and we typically don't build with -g3.
> 
> GCC is pretty much the perfect candidate for a -g3 build.  All 
> those macros...
> 
> The needed gdb changes have been in since right around when I added
> that patch to the incremental branch.  Anybody with a > 3 year old
> gdb should upgrade :-)
Hard to argue with that :-)  Gone are the days when I'd build a binary
tool of some sort and use it for many years thereafter.  I doubt
there's any binary on my boxes older than a year...

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJOjx63AAoJEBRtltQi2kC7fXoH/13uE6l2klTOFPrAKbTszo5s
0fxtmLD9NQWyeOFuGL4P9O9J6rChdulFvY9oNlWUrJIwF7WTOp4FjqNZnhvzoIT8
zEqoT8yVO7pNS7KMyRbxJxz5iEx8pX0YW2O2Rl/qZGy/hFKatqaOgz/RuBZy4lg2
NpiKWULKRsc66FxPKhCPMqtSd338XOhC0S67D2GuK1qD93SFDEyoQbaViieMlmoo
qr5oFn1052byWd3J1cPbu5vv76YLnzPEmBybm0k/ZaoGFC/JidDghQvR9uHtBbbl
LLsFIej62rzCLWZTfbgaiAfKZv79msjhZIrhv8T9iSAolUG4KDvLCvP8SbUg6XI=
=KKKR
-----END PGP SIGNATURE-----
diff mbox

Patch

Index: gcc/ChangeLog

2011-09-22  Lawrence Crowl  <crowl@google.com>

	* tree.h (tree_check): New.
	(TREE_CHECK): Use inline function above instead of __extension__.
	(tree_not_check): New.
	(TREE_NOT_CHECK): Use inline function above instead of __extension__.
	(tree_check2): New.
	(TREE_CHECK2): Use inline function above instead of __extension__.
	(tree_not_check2): New.
	(TREE_NOT_CHECK2): Use inline function above instead of __extension__.
	(tree_check3): New.
	(TREE_CHECK3): Use inline function above instead of __extension__.
	(tree_not_check3): New.
	(TREE_NOT_CHECK3): Use inline function above instead of __extension__.
	(tree_check4): New.
	(TREE_CHECK4): Use inline function above instead of __extension__.
	(tree_not_check4): New.
	(TREE_NOT_CHECK4): Use inline function above instead of __extension__.
	(tree_check5): New.
	(TREE_CHECK5): Use inline function above instead of __extension__.
	(tree_not_check5): New.
	(TREE_NOT_CHECK5): Use inline function above instead of __extension__.
	(contains_struct_check): New.
	(CONTAINS_STRUCT_CHECK): Use inline function above instead of
	__extension__.
	(tree_class_check): New.
	(TREE_CLASS_CHECK): Use inline function above instead of __extension__.
	(tree_range_check): New.
	(TREE_RANGE_CHECK): Use inline function above instead of __extension__.
	(omp_clause_subcode_check): New.
	(OMP_CLAUSE_SUBCODE_CHECK): Use inline function above instead of
	__extension__.
	(omp_clause_range_check): New.
	(OMP_CLAUSE_RANGE_CHECK): Use inline function above instead of
	__extension__.
	(expr_check): New.
	(EXPR_CHECK): Use inline function above instead of __extension__.
	(non_type_check): New.
	(NON_TYPE_CHECK): Use inline function above instead of __extension__.
	(tree_vec_elt_check): New.
	(TREE_VEC_ELT_CHECK): Use inline function above instead of
	__extension__.
	(omp_clause_elt_check): New.
	(OMP_CLAUSE_ELT_CHECK): Use inline function above instead of
	__extension__.
	(tree_operand_check): New.
	(TREE_OPERAND_CHECK): Use inline function above instead of
	__extension__.
	(tree_operand_check_code): New.
	(TREE_OPERAND_CHECK_CODE): Use inline function above instead of
	__extension__.
	(TREE_CHAIN): Simplify implementation.
	(TREE_TYPE): Simplify implementation.
	(tree_operand_length): Move for compilation dependences.


Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 179074)
+++ gcc/tree.h	(working copy)
@@ -737,195 +737,122 @@  enum tree_node_structure_enum {
    is accessed incorrectly. The macros die with a fatal error.  */
 #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
 
-#define TREE_CHECK(T, CODE) __extension__				\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != (CODE))					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, 	\
-			 (CODE), 0);					\
-    __t; })
+#define TREE_CHECK(T, CODE) \
+(tree_check ((T), __FILE__, __LINE__, __FUNCTION__, (CODE)))
+/* ((typeof (T)) tree_check ((T), __FILE__, __LINE__, __FUNCTION__, (CODE))) */
 
-#define TREE_NOT_CHECK(T, CODE) __extension__				\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) == (CODE))					\
-      tree_not_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,	\
-			     (CODE), 0);				\
-    __t; })
+#define TREE_NOT_CHECK(T, CODE) \
+(tree_not_check ((T), __FILE__, __LINE__, __FUNCTION__, (CODE)))
+/* ((typeof (T)) tree_not_check ((T), __FILE__, __LINE__, __FUNCTION__, (CODE))) */
 
-#define TREE_CHECK2(T, CODE1, CODE2) __extension__			\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != (CODE1)					\
-	&& TREE_CODE (__t) != (CODE2))					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,		\
- 			 (CODE1), (CODE2), 0);				\
-    __t; })
+#define TREE_CHECK2(T, CODE1, CODE2) \
+(tree_check2 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2)))
+/* ((typeof (T)) tree_check2 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2))) */
 
-#define TREE_NOT_CHECK2(T, CODE1, CODE2) __extension__			\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) == (CODE1)					\
-	|| TREE_CODE (__t) == (CODE2))					\
-      tree_not_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,	\
-			     (CODE1), (CODE2), 0);			\
-    __t; })
+#define TREE_NOT_CHECK2(T, CODE1, CODE2) \
+( tree_not_check2 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2)))
+/* ((typeof (T)) tree_not_check2 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2))) */
 
-#define TREE_CHECK3(T, CODE1, CODE2, CODE3) __extension__		\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != (CODE1)					\
-	&& TREE_CODE (__t) != (CODE2)					\
-	&& TREE_CODE (__t) != (CODE3))					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,		\
-			     (CODE1), (CODE2), (CODE3), 0);		\
-    __t; })
+#define TREE_CHECK3(T, CODE1, CODE2, CODE3) \
+(tree_check3 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2), (CODE3)))
+/* ((typeof (T)) tree_check3 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2), (CODE3))) */
 
-#define TREE_NOT_CHECK3(T, CODE1, CODE2, CODE3) __extension__		\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) == (CODE1)					\
-	|| TREE_CODE (__t) == (CODE2)					\
-	|| TREE_CODE (__t) == (CODE3))					\
-      tree_not_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,	\
-			     (CODE1), (CODE2), (CODE3), 0);		\
-    __t; })
+#define TREE_NOT_CHECK3(T, CODE1, CODE2, CODE3) \
+(tree_not_check3 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2), (CODE3)))
+/* ((typeof (T)) tree_not_check3 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2), (CODE3))) */
 
-#define TREE_CHECK4(T, CODE1, CODE2, CODE3, CODE4) __extension__	\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != (CODE1)					\
-	&& TREE_CODE (__t) != (CODE2)					\
-	&& TREE_CODE (__t) != (CODE3)					\
-	&& TREE_CODE (__t) != (CODE4))					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,		\
-			     (CODE1), (CODE2), (CODE3), (CODE4), 0);	\
-    __t; })
+#define TREE_CHECK4(T, CODE1, CODE2, CODE3, CODE4) \
+(tree_check4 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2), (CODE3), (CODE4)))
+/* ((typeof (T)) tree_check4 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2), (CODE3), (CODE4))) */
 
-#define TREE_NOT_CHECK4(T, CODE1, CODE2, CODE3, CODE4) __extension__	\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) == (CODE1)					\
-	|| TREE_CODE (__t) == (CODE2)					\
-	|| TREE_CODE (__t) == (CODE3)					\
-	|| TREE_CODE (__t) == (CODE4))					\
-      tree_not_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,	\
-			     (CODE1), (CODE2), (CODE3), (CODE4), 0);	\
-    __t; })
+#define TREE_NOT_CHECK4(T, CODE1, CODE2, CODE3, CODE4) \
+(tree_not_check4 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2), (CODE3), (CODE4)))
+/* ((typeof (T)) tree_not_check4 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2), (CODE3), (CODE4))) */
 
-#define TREE_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) __extension__	\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != (CODE1)					\
-	&& TREE_CODE (__t) != (CODE2)					\
-	&& TREE_CODE (__t) != (CODE3)					\
-	&& TREE_CODE (__t) != (CODE4)					\
-	&& TREE_CODE (__t) != (CODE5))					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,		\
-			     (CODE1), (CODE2), (CODE3), (CODE4), (CODE5), 0);\
-    __t; })
+#define TREE_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) \
+(tree_check5 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2), (CODE3), (CODE4), (CODE5)))
+/* ((typeof (T)) tree_check5 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                           (CODE1), (CODE2), (CODE3), (CODE4), (CODE5))) */
 
-#define TREE_NOT_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) __extension__ \
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) == (CODE1)					\
-	|| TREE_CODE (__t) == (CODE2)					\
-	|| TREE_CODE (__t) == (CODE3)					\
-	|| TREE_CODE (__t) == (CODE4)					\
-	|| TREE_CODE (__t) == (CODE5))					\
-      tree_not_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,	\
-			     (CODE1), (CODE2), (CODE3), (CODE4), (CODE5), 0);\
-    __t; })
+#define TREE_NOT_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) \
+(tree_not_check5 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2), (CODE3), (CODE4), (CODE5)))
+/* ((typeof (T)) tree_not_check5 ((T), __FILE__, __LINE__, __FUNCTION__, \
+                               (CODE1), (CODE2), (CODE3), (CODE4), (CODE5))) */
 
-#define CONTAINS_STRUCT_CHECK(T, STRUCT) __extension__			\
-({  __typeof (T) const __t = (T);					\
-  if (tree_contains_struct[TREE_CODE(__t)][(STRUCT)] != 1)		\
-      tree_contains_struct_check_failed (__t, (STRUCT), __FILE__, __LINE__,	\
-			       __FUNCTION__);				\
-    __t; })
+#define CONTAINS_STRUCT_CHECK(T, STRUCT) \
+(contains_struct_check ((T), (STRUCT), \
+                                     __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) contains_struct_check ((T), (STRUCT), \
+                                     __FILE__, __LINE__, __FUNCTION__)) */
 
-#define TREE_CLASS_CHECK(T, CLASS) __extension__			\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE_CLASS (TREE_CODE(__t)) != (CLASS))			\
-      tree_class_check_failed (__t, (CLASS), __FILE__, __LINE__,	\
-			       __FUNCTION__);				\
-    __t; })
+#define TREE_CLASS_CHECK(T, CLASS) \
+(tree_class_check ((T), (CLASS), \
+                                __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) tree_class_check ((T), (CLASS), \
+                                __FILE__, __LINE__, __FUNCTION__)) */
 
-#define TREE_RANGE_CHECK(T, CODE1, CODE2) __extension__			\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) < (CODE1) || TREE_CODE (__t) > (CODE2))		\
-      tree_range_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,	\
-			       (CODE1), (CODE2));			\
-    __t; })
+#define TREE_RANGE_CHECK(T, CODE1, CODE2) \
+(tree_range_check ((T), (CODE1), (CODE2), \
+                                __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) tree_range_check ((T), (CODE1), (CODE2), \
+                                __FILE__, __LINE__, __FUNCTION__)) */
 
-#define OMP_CLAUSE_SUBCODE_CHECK(T, CODE) __extension__			\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != OMP_CLAUSE)					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,  	\
-			 OMP_CLAUSE, 0);				\
-    if (__t->omp_clause.code != (CODE))					\
-      omp_clause_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, 	\
-			       (CODE));					\
-    __t; })
+#define OMP_CLAUSE_SUBCODE_CHECK(T, CODE) \
+(omp_clause_subcode_check ((T), (CODE), \
+                                        __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) omp_clause_subcode_check ((T), (CODE), \
+                                        __FILE__, __LINE__, __FUNCTION__)) */
 
-#define OMP_CLAUSE_RANGE_CHECK(T, CODE1, CODE2) __extension__		\
-({  __typeof (T) const __t = (T);					\
-    if (TREE_CODE (__t) != OMP_CLAUSE)					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,  	\
-			 OMP_CLAUSE, 0);				\
-    if ((int) __t->omp_clause.code < (int) (CODE1)			\
-        || (int) __t->omp_clause.code > (int) (CODE2))			\
-      omp_clause_range_check_failed (__t, __FILE__, __LINE__,		\
-				     __FUNCTION__, (CODE1), (CODE2));	\
-    __t; })
+#define OMP_CLAUSE_RANGE_CHECK(T, CODE1, CODE2) \
+(omp_clause_range_check ((T), (CODE1), (CODE2), \
+                                      __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) omp_clause_range_check ((T), (CODE1), (CODE2), \
+                                      __FILE__, __LINE__, __FUNCTION__)) */
 
 /* These checks have to be special cased.  */
-#define EXPR_CHECK(T) __extension__					\
-({  __typeof (T) const __t = (T);					\
-    char const __c = TREE_CODE_CLASS (TREE_CODE (__t));			\
-    if (!IS_EXPR_CODE_CLASS (__c))					\
-      tree_class_check_failed (__t, tcc_expression, __FILE__, __LINE__,	\
-			       __FUNCTION__);				\
-    __t; })
+#define EXPR_CHECK(T) \
+(expr_check ((T), __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) expr_check ((T), __FILE__, __LINE__, __FUNCTION__)) */
 
 /* These checks have to be special cased.  */
-#define NON_TYPE_CHECK(T) __extension__					\
-({  __typeof (T) const __t = (T);					\
-    if (TYPE_P (__t))							\
-      tree_not_class_check_failed (__t, tcc_type, __FILE__, __LINE__,	\
-				   __FUNCTION__);			\
-    __t; })
+#define NON_TYPE_CHECK(T) \
+(non_type_check ((T), __FILE__, __LINE__, __FUNCTION__))
+/* ((typeof (T)) non_type_check ((T), __FILE__, __LINE__, __FUNCTION__)) */
 
-#define TREE_VEC_ELT_CHECK(T, I) __extension__				\
-(*({__typeof (T) const __t = (T);					\
-    const int __i = (I);						\
-    if (TREE_CODE (__t) != TREE_VEC)					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,		\
-  			 TREE_VEC, 0);					\
-    if (__i < 0 || __i >= __t->vec.length)				\
-      tree_vec_elt_check_failed (__i, __t->vec.length,			\
-				 __FILE__, __LINE__, __FUNCTION__);	\
-    &__t->vec.a[__i]; }))
+#define TREE_VEC_ELT_CHECK(T, I) \
+(*(CONST_CAST2 (tree *, typeof (T)*, \
+     tree_vec_elt_check ((T), (I), __FILE__, __LINE__, __FUNCTION__))))
 
-#define OMP_CLAUSE_ELT_CHECK(T, I) __extension__			\
-(*({__typeof (T) const __t = (T);					\
-    const int __i = (I);						\
-    if (TREE_CODE (__t) != OMP_CLAUSE)					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,  	\
-			 OMP_CLAUSE, 0);				\
-    if (__i < 0 || __i >= omp_clause_num_ops [__t->omp_clause.code])	\
-      omp_clause_operand_check_failed (__i, __t, __FILE__, __LINE__,	\
-	                               __FUNCTION__);			\
-    &__t->omp_clause.ops[__i]; }))
+#define OMP_CLAUSE_ELT_CHECK(T, I) \
+(*(omp_clause_elt_check ((T), (I), \
+                                      __FILE__, __LINE__, __FUNCTION__)))
+/* (*((typeof (T)*) omp_clause_elt_check ((T), (I), \
+                                      __FILE__, __LINE__, __FUNCTION__))) */
 
 /* Special checks for TREE_OPERANDs.  */
-#define TREE_OPERAND_CHECK(T, I) __extension__				\
-(*({__typeof (T) const __t = EXPR_CHECK (T);				\
-    const int __i = (I);						\
-    if (__i < 0 || __i >= TREE_OPERAND_LENGTH (__t))			\
-      tree_operand_check_failed (__i, __t,				\
-				 __FILE__, __LINE__, __FUNCTION__);	\
-    &__t->exp.operands[__i]; }))
+#define TREE_OPERAND_CHECK(T, I) \
+(*(CONST_CAST2 (tree*, typeof (T)*, \
+     tree_operand_check ((T), (I), __FILE__, __LINE__, __FUNCTION__))))
 
-#define TREE_OPERAND_CHECK_CODE(T, CODE, I) __extension__		\
-(*({__typeof (T) const __t = (T);					\
-    const int __i = (I);						\
-    if (TREE_CODE (__t) != CODE)					\
-      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, (CODE), 0);\
-    if (__i < 0 || __i >= TREE_OPERAND_LENGTH (__t))			\
-      tree_operand_check_failed (__i, __t,				\
-				 __FILE__, __LINE__, __FUNCTION__);	\
-    &__t->exp.operands[__i]; }))
+#define TREE_OPERAND_CHECK_CODE(T, CODE, I) \
+(*(tree_operand_check_code ((T), (CODE), (I), \
+                                         __FILE__, __LINE__, __FUNCTION__)))
+/* (*((typeof (T)*) tree_operand_check_code ((T), (CODE), (I), \
+                                         __FILE__, __LINE__, __FUNCTION__))) */
 
 /* Nodes are chained together for many purposes.
    Types are chained together to record them for being output to the debugger
@@ -936,17 +863,15 @@  enum tree_node_structure_enum {
    Often lists of things are represented by TREE_LIST nodes that
    are chained together.  */
 
-#define TREE_CHAIN(NODE) __extension__ \
-(*({__typeof (NODE) const __t = CONTAINS_STRUCT_CHECK (NODE, TS_COMMON);\
-    &__t->common.chain; }))
+#define TREE_CHAIN(NODE) \
+(CONTAINS_STRUCT_CHECK (NODE, TS_COMMON)->common.chain)
 
 /* In all nodes that are expressions, this is the data type of the expression.
    In POINTER_TYPE nodes, this is the type that the pointer points to.
    In ARRAY_TYPE nodes, this is the type of the elements.
    In VECTOR_TYPE nodes, this is the type of the elements.  */
-#define TREE_TYPE(NODE) __extension__ \
-(*({__typeof (NODE) const __t = CONTAINS_STRUCT_CHECK (NODE, TS_TYPED); \
-    &__t->typed.type; }))
+#define TREE_TYPE(NODE) \
+(CONTAINS_STRUCT_CHECK (NODE, TS_TYPED)->typed.type)
 
 extern void tree_contains_struct_check_failed (const_tree,
 					       const enum tree_node_structure_enum,
@@ -3671,6 +3596,253 @@  union GTY ((ptr_alias (union lang_tree_n
   struct tree_optimization_option GTY ((tag ("TS_OPTIMIZATION"))) optimization;
   struct tree_target_option GTY ((tag ("TS_TARGET_OPTION"))) target_option;
 };
+
+
+#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
+
+static inline tree
+tree_check (const_tree __t, const char *__f, int __l, const char *__g,
+            enum tree_code __c)
+{
+  if (TREE_CODE (__t) != __c)
+    tree_check_failed (__t, __f, __l, __g, __c, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_not_check (const_tree __t, const char *__f, int __l, const char *__g,
+                enum tree_code __c)
+{
+  if (TREE_CODE (__t) == __c)
+    tree_not_check_failed (__t, __f, __l, __g, __c, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_check2 (const_tree __t, const char *__f, int __l, const char *__g,
+             enum tree_code __c1, enum tree_code __c2)
+{
+  if (TREE_CODE (__t) != __c1
+      && TREE_CODE (__t) != __c2)
+    tree_check_failed (__t, __f, __l, __g, __c1, __c2, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_not_check2 (const_tree __t, const char *__f, int __l, const char *__g,
+                 enum tree_code __c1, enum tree_code __c2)
+{
+  if (TREE_CODE (__t) == __c1
+      || TREE_CODE (__t) == __c2)
+    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_check3 (const_tree __t, const char *__f, int __l, const char *__g,
+             enum tree_code __c1, enum tree_code __c2, enum tree_code __c3)
+{
+  if (TREE_CODE (__t) != __c1
+      && TREE_CODE (__t) != __c2
+      && TREE_CODE (__t) != __c3)
+    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_not_check3 (const_tree __t, const char *__f, int __l, const char *__g,
+                 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3)
+{
+  if (TREE_CODE (__t) == __c1
+      || TREE_CODE (__t) == __c2
+      || TREE_CODE (__t) == __c3)
+    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_check4 (const_tree __t, const char *__f, int __l, const char *__g,
+             enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+             enum tree_code __c4)
+{
+  if (TREE_CODE (__t) != __c1
+      && TREE_CODE (__t) != __c2
+      && TREE_CODE (__t) != __c3
+      && TREE_CODE (__t) != __c4)
+    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_not_check4 (const_tree __t, const char *__f, int __l, const char *__g,
+                 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+                 enum tree_code __c4)
+{
+  if (TREE_CODE (__t) == __c1
+      || TREE_CODE (__t) == __c2
+      || TREE_CODE (__t) == __c3
+      || TREE_CODE (__t) == __c4)
+    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_check5 (const_tree __t, const char *__f, int __l, const char *__g,
+             enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+             enum tree_code __c4, enum tree_code __c5)
+{
+  if (TREE_CODE (__t) != __c1
+      && TREE_CODE (__t) != __c2
+      && TREE_CODE (__t) != __c3
+      && TREE_CODE (__t) != __c4
+      && TREE_CODE (__t) != __c5)
+    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_not_check5 (const_tree __t, const char *__f, int __l, const char *__g,
+                 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+                 enum tree_code __c4, enum tree_code __c5)
+{
+  if (TREE_CODE (__t) == __c1
+      || TREE_CODE (__t) == __c2
+      || TREE_CODE (__t) == __c3
+      || TREE_CODE (__t) == __c4
+      || TREE_CODE (__t) == __c5)
+    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5, 0);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+contains_struct_check (const_tree __t, const enum tree_node_structure_enum __s,
+                       const char *__f, int __l, const char *__g)
+{
+  if (tree_contains_struct[TREE_CODE(__t)][__s] != 1)
+      tree_contains_struct_check_failed (__t, __s, __f, __l, __g);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_class_check (const_tree __t, const enum tree_code_class __class,
+                  const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE_CLASS (TREE_CODE(__t)) != __class)
+    tree_class_check_failed (__t, __class, __f, __l, __g);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+tree_range_check (const_tree __t,
+                  enum tree_code __code1, enum tree_code __code2,
+                  const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE (__t) < __code1 || TREE_CODE (__t) > __code2)
+    tree_range_check_failed (__t, __f, __l, __g, __code1, __code2);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+omp_clause_subcode_check (const_tree __t, enum omp_clause_code __code,
+                          const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE (__t) != OMP_CLAUSE)
+    tree_check_failed (__t, __f, __l, __g, OMP_CLAUSE, 0);
+  if (__t->omp_clause.code != __code)
+    omp_clause_check_failed (__t, __f, __l, __g, __code);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree
+omp_clause_range_check (const_tree __t,
+                        enum omp_clause_code __code1,
+                        enum omp_clause_code __code2,
+                        const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE (__t) != OMP_CLAUSE)
+    tree_check_failed (__t, __f, __l, __g, OMP_CLAUSE, 0);
+  if ((int) __t->omp_clause.code < (int) __code1
+      || (int) __t->omp_clause.code > (int) __code2)
+    omp_clause_range_check_failed (__t, __f, __l, __g, __code1, __code2);
+  return CONST_CAST_TREE (__t);
+}
+
+/* These checks have to be special cased.  */
+static inline tree
+expr_check (const_tree __t, const char *__f, int __l, const char *__g)
+{
+  char const __c = TREE_CODE_CLASS (TREE_CODE (__t));
+  if (!IS_EXPR_CODE_CLASS (__c))
+    tree_class_check_failed (__t, tcc_expression, __f, __l, __g);
+  return CONST_CAST_TREE (__t);
+}
+
+/* These checks have to be special cased.  */
+static inline tree
+non_type_check (const_tree __t, const char *__f, int __l, const char *__g)
+{
+  if (TYPE_P (__t))
+    tree_not_class_check_failed (__t, tcc_type, __f, __l, __g);
+  return CONST_CAST_TREE (__t);
+}
+
+static inline tree *
+tree_vec_elt_check (const_tree __t, int __i,
+                    const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE (__t) != TREE_VEC)
+    tree_check_failed (__t, __f, __l, __g, TREE_VEC, 0);
+  if (__i < 0 || __i >= __t->vec.length)
+    tree_vec_elt_check_failed (__i, __t->vec.length, __f, __l, __g);
+  return &CONST_CAST_TREE (__t)->vec.a[__i];
+}
+
+static inline tree *
+omp_clause_elt_check (const_tree __t, int __i,
+                      const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE (__t) != OMP_CLAUSE)
+    tree_check_failed (__t, __f, __l, __g, OMP_CLAUSE, 0);
+  if (__i < 0 || __i >= omp_clause_num_ops [__t->omp_clause.code])
+    omp_clause_operand_check_failed (__i, __t, __f, __l, __g);
+  return &CONST_CAST_TREE (__t)->omp_clause.ops[__i];
+}
+
+/* Compute the number of operands in an expression node NODE.  For
+   tcc_vl_exp nodes like CALL_EXPRs, this is stored in the node itself,
+   otherwise it is looked up from the node's code.  */
+static inline int
+tree_operand_length (const_tree node)
+{
+  if (VL_EXP_CLASS_P (node))
+    return VL_EXP_OPERAND_LENGTH (node);
+  else
+    return TREE_CODE_LENGTH (TREE_CODE (node));
+}
+
+/* Special checks for TREE_OPERANDs.  */
+static inline tree *
+tree_operand_check (const_tree __t, int __i,
+                    const char *__f, int __l, const char *__g)
+{
+  const_tree __u = EXPR_CHECK (__t);
+  if (__i < 0 || __i >= TREE_OPERAND_LENGTH (__u))
+    tree_operand_check_failed (__i, __u, __f, __l, __g);
+  return &CONST_CAST_TREE (__u)->exp.operands[__i];
+}
+
+static inline tree *
+tree_operand_check_code (const_tree __t, enum tree_code __code, int __i,
+                         const char *__f, int __l, const char *__g)
+{
+  if (TREE_CODE (__t) != __code)
+    tree_check_failed (__t, __f, __l, __g, __code, 0);
+  if (__i < 0 || __i >= TREE_OPERAND_LENGTH (__t))
+    tree_operand_check_failed (__i, __t, __f, __l, __g);
+  return &CONST_CAST_TREE (__t)->exp.operands[__i];
+}
+
+#endif
 
 /* Standard named or nameless data types of the C compiler.  */
 
@@ -5791,18 +5963,6 @@  extern tree build_personality_function (
 
 void init_inline_once (void);
 
-/* Compute the number of operands in an expression node NODE.  For
-   tcc_vl_exp nodes like CALL_EXPRs, this is stored in the node itself,
-   otherwise it is looked up from the node's code.  */
-static inline int
-tree_operand_length (const_tree node)
-{
-  if (VL_EXP_CLASS_P (node))
-    return VL_EXP_OPERAND_LENGTH (node);
-  else
-    return TREE_CODE_LENGTH (TREE_CODE (node));
-}
-
 /* Abstract iterators for CALL_EXPRs.  These static inline definitions
    have to go towards the end of tree.h so that union tree_node is fully
    defined by this point.  */