This is the mail archive of the gdb-patches@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]
Other format: [Raw text]

Re: [RFC] const qualifiers in gdb.c++/method.exp


Interesting.  Let me walk through this.

The class is:

  class A {
  public:
    int x;
    int y;
    int foo (int arg);
    int bar (int arg) const;
    int baz (int arg, char c) volatile;
    int qux (int arg, float f) const volatile;
  };

The test script sets breakpoints on A::foo and A::bar and does "print
this".  gdb has to show a type for "this", and the test script has to
match that type.

In _The C++ Programming Language_, Stroustrop, 3rd edition,
section 10.2.7 ("Self-Reference") talks about the type of "this":

  In a nonstatic member function, the keyword _this_ is a pointer to the
  object for which the function was invoked.  In a non-_const_ member
  function of class _X_, the type of _this_ is _X*_.  However, _this_
  is not an ordinary variable; it is not possible to take the address of
  _this_ or to assign to _this_.  In a _const_ member function of class
  _X_, the type of _this_ is _const X*_ to prevent modification of the
  object itself (see also S5.4.1).

===

In A::foo, the right type of "this" is "A *".  Here are the actual
types that I am seeing:

  "A *"
    native i686-pc-linux-gnu, gcc 2.95.3,         -gstabs+
    native i686-pc-linux-gnu, gcc 3.0.2,          -gstabs+
    native i686-pc-linux-gnu, gcc HEAD,           -gstabs+
    native i686-pc-linux-gnu, gcc gcc-3_0-branch, -gstabs+

  "A * const"
    native i686-pc-linux-gnu, gcc 2.95.3,         -gdwarf-2
    native i686-pc-linux-gnu, gcc 3.0.2,          -gdwarf-2
    native i686-pc-linux-gnu, gcc HEAD,           -gdwarf-2
    native i686-pc-linux-gnu, gcc gcc-3_0-branch, -gdwarf-2

The difference between "A *" and "A * const" is that "A * const"
does not allow assigning to the pointer itself.  Here is an example:

  class A { public: int x; class A * next; };
  void foo (A * p1, A * const p2)
  {
    p1->x = 0;         // okay
    p1    = p1->next;  // okay
    p2->x = 0;         // okay
    p2    = p2->next;  // illegal
  }

So I'm completely happy with fragment #1:

  @@ -103,7 +103,7 @@ gdb_expect {
   
   send_gdb "print this\n"
   gdb_expect {
  -   -re "\\$\[0-9\]* = \\(A \\*\\) $hex\r\n$gdb_prompt $" {
  +   -re "\\$\[0-9\]* = \\(A \\*( const)?\\) $hex\r\n$gdb_prompt $" {
	  pass "print this (in foo)"
      }
      -re ".*$gdb_prompt $" { fail "print this (in foo)" }

===

The next fragment deals with A::bar, which is a const method.  By the book,
the type of "this" is "const A *".  This means that "this" points to a
object which cannot be modified.  Additionally, the "this" pointer itself
cannot be changed, so it is also okay if the type of "this" to be
"const A * const".

Here are the actual types:

  "A *"
    native i686-pc-linux-gnu, gcc 2.95.3,         -gstabs+
    native i686-pc-linux-gnu, gcc 3.0.2,          -gstabs+
    native i686-pc-linux-gnu, gcc HEAD,           -gstabs+
    native i686-pc-linux-gnu, gcc gcc-3_0-branch, -gstabs+

  "A * const"
    native i686-pc-linux-gnu, gcc 3.0.2,          -gdwarf-2
    native i686-pc-linux-gnu, gcc HEAD,           -gdwarf-2
    native i686-pc-linux-gnu, gcc gcc-3_0-branch, -gdwarf-2

  "const A * const"
    native i686-pc-linux-gnu, gcc 2.95.3,         -gdwarf-2

The first seven of these are wrong.  The type needs to have a "const A *"
in it, rather than an "A *".

So in fragment #2:

  @@ -154,7 +154,7 @@ gdb_expect {
	  pass "print this (in bar)"
	}
      }
  -   -re "\\$\[0-9\]* = \\(A \\*\\) $hex\r\n$gdb_prompt $" {
  +   -re "\\$\[0-9\]* = \\((const )?A \\*( const)?\\) $hex\r\n$gdb_prompt $" {
	global gcc_compiled
	if {$gcc_compiled} {
	  pass "print this (in bar)"

The original line is wrong because it should have "const A" all
the time.  The line should read:

  +   -re "\\$\[0-9\]* = \\(const A \\*( const)?\\) $hex\r\n$gdb_prompt $" {

The optional "( const)?" after the "*" is fine.

It's quite likely that gdb is passing the types through from gcc, which
gets into the whole philosophical issue about what to do when gdb exposes
a gcc bug.  I believe in writing the tests correctly and then filing a
bug report upstream to gcc.

===

Fragment 3:

  @@ -203,7 +203,7 @@ gdb_expect {
   
   send_gdb "print this\n"
   gdb_expect {
  -   -re "\\$\[0-9\]* = \\(funk \\*\\) $hex\r\n$gdb_prompt $" {
  +   -re "\\$\[0-9\]* = \\(funk \\*( const)?\\) $hex\r\n$gdb_prompt $" {
	  pass "print this in getFunky"
      }
      -re ".*$gdb_prompt $" { fail "print this in getfunky" }

This is fine.  My stabs+ logs show a type of "funk *", my dwarf-2
logs show a type of "funk * const", and either type is acceptable.

===

Fragment 4

  @@ -226,7 +226,7 @@ gdb_expect {
 
   send_gdb "ptype A\n"
   gdb_expect {
  -   -re "type = class A \{\r\n\[ \]*public:\r\n\[ \]*int x;\r\n\[ \]*int y;\r\n\r\n\[ \]*A & operator=\\(A const ?&\\);\r\n\[ \]*A\\(A const ?&\\);\r\n\[ \]*A\\((void|)\\);\r\n\[ \]*int foo\\(int\\);\r\n\[ \]*int bar\\(int\\) const;\r\n\[ \]*int baz\\(int, char\\) volatile;\r\n\[ \]*int qux\\(int, float\\) (const volatile|volatile const);\r\n\}\r\n$gdb_prompt $" {
  +   -re "type = class A \{\r\n\[ \]*public:\r\n\[ \]*int x;\r\n\[ \]*int y;\r\n\r\n\[ \]*A & operator=\\(A const ?&\\);\r\n\[ \]*A\\((A const|const A) ?&\\);\r\n\[ \]*A\\((void|)\\);\r\n\[ \]*int foo\\(int\\);\r\n\[ \]*int bar\\(int\\) const;\r\n\[ \]*int baz\\(int, char\\) volatile;\r\n\[ \]*int qux\\(int, float\\) (const volatile|volatile const);\r\n\}\r\n$gdb_prompt $" {
	 pass "ptype A"
      }
      -re "type = class A \{\r\n\[ \]*public:\r\n\[ \]*int x;\r\n\[ \]*int y;\r\n\r\n\[ \]*int foo\\(int\\);\r\n\[ \]*int bar\\(int\\) const;\r\n\[ \]*int baz\\(int, char\\);\r\n\[ \]*int qux\\(int, float\\) const;\r\n\}\r\n$gdb_prompt $" {

Hmmm, yeah, this is fine.  "A const &" and "const A &" mean the same thing
so gdb is okay if it emits either one.

===

So 3 of the 4 fragments are acceptable.  I think that in fragment 2,
the first "const" is mandatory.  This will result in some FAILs, which
will probably turn into bug reports against gcc.

Finally, you need to update the copyright date on line 1 of method.exp.


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