This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

software archaeology: fixing method calls



This is kind of interesting.  

Here are some excerpts from gdbtypes.h:

enum type_code
  {
    ...
    TYPE_CODE_FUNC,		/* Function type */
    ...
    TYPE_CODE_METHOD,		/* Method type */
    ...
  };
...

struct type
  {
    /* Code for kind of type */
    enum type_code code;
    ...

    /* Number of fields described for this type */
    short nfields;

    /* For structure and union types, a description of each field.
        ...
       For a function type, a "field" for each parameter type.
        ...
     */
    struct field
      {
        ...
      }
     *fields;

    /* Slot to point to additional language-specific fields of this type.  */
    union type_specific
      {
	/* ARG_TYPES is for TYPE_CODE_METHOD.
	   Contains the type of each argument, ending with a void type
	   after the last argument for normal member functions or a NULL
	   pointer after the last argument for functions with variable
	   arguments.  */

	struct type **arg_types;
        ...
      }
    type_specific;
  };


Now, this is a bit odd:

- For TYPE_CODE_FUNC, the types of the arguments are stored in
  `fields', just as if they were members of a structure. This lets us
  store the names of the arguments.

- However, for TYPE_CODE_METHOD, the types of the arguments are stored
  in `type_specific.arg_types'.

Why is this?

Back in 1992, TYPE_CODE_FUNC used `type_specific.arg_types' as well.
In 1995, they migrated to fields, for reasons I don't yet understand.
TYPE_CODE_METHOD was left as is.

The test suite detects some problems this causes when we try to invoke
methods that take arguments by reference:

FAIL: gdb.c++/classes.exp: base class (&param)->a
FAIL: gdb.c++/classes.exp: base class (&param)->x
FAIL: gdb.c++/classes.exp: inherited class (&param)->a
FAIL: gdb.c++/classes.exp: inherited class (&param)->x

To remind folks how C++ reference arguments work: you declare your
function or member function like this:

    foo (int &x)  /* foo takes an integer variable by reference */
    {
      x++;
    }

and then you call it like this:

    {
      int boo = 1;

      foo (boo);

      /* Now boo is 2.  */
    }

Underneath the hood, C++ passes boo's address to foo, and foo
automatically dereferences that pointer for any operations on x.

However, this means that invoking functions that expect reference
arguments is impossible if you don't know the types of the arguments:
you can't tell whether to pass boo's value (1), or boo's address
(&boo).

In valops.c, hand_function_call does have the necessary logic to deal
with this correctly: if the formal parameter's type is a reference, it
takes the address of the actual parameter.  Unfortunately, if we're
invoking a method, the argument types are in a different place, and
hand_function_call doesn't check for them there.

There are two alternatives:

- We could change hand_function_call to find method argument types
  where they live now.

- We could change the definition of TYPE_CODE_METHOD to put the
  arguments in the same place TYPE_CODE_FUNCTION does.

I prefer the latter, since it gives similar types similar
representations.

Comments?


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]