Passing DW_TAG_typedef as the type to DIBuilder's createFunction

Hi David, I'm seeing an assertion failure when passing this node

   !{i32 786454, metadata <badref>, metadata <badref>, metadata !"fn_t", i32 5, i64 0, i64 0, i64 0, i32 0, metadata <badref>} ; [ DW_TAG_typedef ] [fn_t] [line 5, size 0, align 0, offset 0] [from ]

as the function type parameter to DIBuilder::createFunction, due to this check
in DebugInfo.cpp:

486 DICompositeType Ty = getType();
487 if (!Ty.Verify())
488 return false;

Is it in fact wrong to pass a typedef here?

Thanks, Duncan.

I can't come up with a way that'd be correct, no. You should be using
createSubroutineType and passing that into the builder. Have example
code where this is coming up?

-eric

Hi Eric,

Hi Eric,

I think you might be ascribing more rigor to the debug info IR than is
due. It's a fairly pragmatic implementation without much thought (so
far as I can tell) to high level principles of types, etc. It's
essentially "how do we describe the stuff we need to produce debug
info".

If the function's type just needs to be a type, then that's all it is
(a function type) & all that's supported by the backend most likely -
there's no particular merit in providing the possibility for that type
to be indirected through a typedef or anything of the sort.

If there's any case where we actually produce different/inferior debug
info because of this representation, then that's a bug worth
considering that might necessitate a change in the IR representation
to allow a function's type to be a typedef.

eg: I wonder what this looks like in GCC debug info, Clang debug info,
and what is correct/good:

typedef int foo(int);
foo bar;

is 'bar' a function of type "int(int)" or a function of type "foo"
which is a typedef of type "int(int)". I suppose it could be the
latter, in which case we should be usincg/allowing a function's type
to be a typedef.

It's not going to come up with anything since bar is unused :slight_smile:

I've been unable to come up with any way to use foo as a type for a
function. If you can come up with one...

-eric

Hi Eric,

Hi David, I'm seeing an assertion failure when passing this node

   !{i32 786454, metadata <badref>, metadata <badref>, metadata !"fn_t",
i32
5, i64 0, i64 0, i64 0, i32 0, metadata <badref>} ; [ DW_TAG_typedef ]
[fn_t] [line 5, size 0, align 0, offset 0] [from ]

as the function type parameter to DIBuilder::createFunction, due to this
check
in DebugInfo.cpp:

486 DICompositeType Ty = getType();
487 if (!Ty.Verify())
488 return false;

Is it in fact wrong to pass a typedef here?

I can't come up with a way that'd be correct, no. You should be using
createSubroutineType and passing that into the builder. Have example
code where this is coming up?

OK, it looks like a DW_TAG_typedef node defines a new type. If the original
type is a subroutine type, I don't see why a typedef of it shouldn't be used
anywhere the original could. After all, it is just an alternative name for
the same thing. You clearly have a different mental model of what a typedef
is, but what is it?

I think you might be ascribing more rigor to the debug info IR than is
due. It's a fairly pragmatic implementation without much thought (so
far as I can tell) to high level principles of types, etc. It's
essentially "how do we describe the stuff we need to produce debug
info".

If the function's type just needs to be a type, then that's all it is
(a function type) & all that's supported by the backend most likely -
there's no particular merit in providing the possibility for that type
to be indirected through a typedef or anything of the sort.

If there's any case where we actually produce different/inferior debug
info because of this representation, then that's a bug worth
considering that might necessitate a change in the IR representation
to allow a function's type to be a typedef.

eg: I wonder what this looks like in GCC debug info, Clang debug info,
and what is correct/good:

typedef int foo(int);
foo bar;

is 'bar' a function of type "int(int)" or a function of type "foo"
which is a typedef of type "int(int)". I suppose it could be the
latter, in which case we should be usincg/allowing a function's type
to be a typedef.

It's not going to come up with anything since bar is unused :slight_smile:

Sure, so make it used...

But then we still don't emit anything about the function (& neither does GCC).
So make it a member function (so we are forced to emit the declaration
even without complicating the example by having to add a definition
(which by necessity cannot use the typedef))... and then we see that
the subprogram description doesn't refer to a function type at all. It
refers to a return type and it has its own parameters directly. (
typedef int foo(int); struct bar { foo f; }; int main() { bar b;
b.f(3); }; )

So that's probably why then: it's irrelevant to DWARF how the function
type is written, the DWARF representation decomposes this & describes
the return type and its parameters separately - whether or not there
is a typedef there. It's possible that some other debug info format we
might support in the future could have greater fidelity here & we'd
have to change/improve the way we represent this in IR, but until then
I think it's simple/safe enough to just describe a function type
directly, ignoring any typedefs.

Hi Eric,

Hi David, I'm seeing an assertion failure when passing this node

   !{i32 786454, metadata <badref>, metadata <badref>, metadata !"fn_t",
i32
5, i64 0, i64 0, i64 0, i32 0, metadata <badref>} ; [ DW_TAG_typedef ]
[fn_t] [line 5, size 0, align 0, offset 0] [from ]

as the function type parameter to DIBuilder::createFunction, due to this
check
in DebugInfo.cpp:

486 DICompositeType Ty = getType();
487 if (!Ty.Verify())
488 return false;

Is it in fact wrong to pass a typedef here?

I can't come up with a way that'd be correct, no. You should be using
createSubroutineType and passing that into the builder. Have example
code where this is coming up?

OK, it looks like a DW_TAG_typedef node defines a new type. If the original
type is a subroutine type, I don't see why a typedef of it shouldn't be used
anywhere the original could. After all, it is just an alternative name for
the same thing. You clearly have a different mental model of what a typedef
is, but what is it?

I think you might be ascribing more rigor to the debug info IR than is
due. It's a fairly pragmatic implementation without much thought (so
far as I can tell) to high level principles of types, etc. It's
essentially "how do we describe the stuff we need to produce debug
info".

If the function's type just needs to be a type, then that's all it is
(a function type) & all that's supported by the backend most likely -
there's no particular merit in providing the possibility for that type
to be indirected through a typedef or anything of the sort.

If there's any case where we actually produce different/inferior debug
info because of this representation, then that's a bug worth
considering that might necessitate a change in the IR representation
to allow a function's type to be a typedef.

eg: I wonder what this looks like in GCC debug info, Clang debug info,
and what is correct/good:

typedef int foo(int);
foo bar;

is 'bar' a function of type "int(int)" or a function of type "foo"
which is a typedef of type "int(int)". I suppose it could be the
latter, in which case we should be usincg/allowing a function's type
to be a typedef.

It's not going to come up with anything since bar is unused :slight_smile:

Sure, so make it used...

Sure.. but...

But then we still don't emit anything about the function (& neither does GCC).
So make it a member function (so we are forced to emit the declaration
even without complicating the example by having to add a definition
(which by necessity cannot use the typedef))... and then we see that
the subprogram description doesn't refer to a function type at all. It
refers to a return type and it has its own parameters directly. (
typedef int foo(int); struct bar { foo f; }; int main() { bar b;
b.f(3); }; )

I couldn't come up with any code to make it the type of a function
rather than a function pointer or a member variable that happens to be
a function pointer. :slight_smile:

So that's probably why then: it's irrelevant to DWARF how the function
type is written, the DWARF representation decomposes this & describes
the return type and its parameters separately - whether or not there
is a typedef there. It's possible that some other debug info format we
might support in the future could have greater fidelity here & we'd
have to change/improve the way we represent this in IR, but until then
I think it's simple/safe enough to just describe a function type
directly, ignoring any typedefs.

*nod*

-eric

Hi Eric,

But then we still don't emit anything about the function (& neither does GCC).
So make it a member function (so we are forced to emit the declaration
even without complicating the example by having to add a definition
(which by necessity cannot use the typedef))... and then we see that
the subprogram description doesn't refer to a function type at all. It
refers to a return type and it has its own parameters directly. (
typedef int foo(int); struct bar { foo f; }; int main() { bar b;
b.f(3); }; )

I couldn't come up with any code to make it the type of a function
rather than a function pointer or a member variable that happens to be
a function pointer. :slight_smile:

I guess you only tried obscure languages like C and C++ :slight_smile: I don't see why it
shouldn't be theoretically possible, for some language. But as David explained
to me, the current design is pragmatic: do something that works for the
front-ends we have; extend when necessary. I've got to admit that as far as
dragonegg is concerned, it looks like there will always be an appropriate
function type floating around that can be used, so I plan to just fix this up
in dragonegg and worry about funky languages when and if they show up one day.

Ciao, Duncan.

Hi Eric,

But then we still don't emit anything about the function (& neither does
GCC).
So make it a member function (so we are forced to emit the declaration
even without complicating the example by having to add a definition
(which by necessity cannot use the typedef))... and then we see that
the subprogram description doesn't refer to a function type at all. It
refers to a return type and it has its own parameters directly. (
typedef int foo(int); struct bar { foo f; }; int main() { bar b;
b.f(3); }; )

I couldn't come up with any code to make it the type of a function
rather than a function pointer or a member variable that happens to be
a function pointer. :slight_smile:

I guess you only tried obscure languages like C and C++ :slight_smile: I don't see why
it
shouldn't be theoretically possible, for some language. But as David

Exactly! :slight_smile:

explained
to me, the current design is pragmatic: do something that works for the
front-ends we have; extend when necessary. I've got to admit that as far as
dragonegg is concerned, it looks like there will always be an appropriate
function type floating around that can be used, so I plan to just fix this
up
in dragonegg and worry about funky languages when and if they show up one
day.

No worries. I just wanted to see how it went and how to create
something that made sense to me.

Thanks!

-eric