From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6767 invoked by alias); 9 Jan 2002 16:53:01 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 6726 invoked from network); 9 Jan 2002 16:52:55 -0000 Received: from unknown (HELO duracef.shout.net) (204.253.184.12) by sources.redhat.com with SMTP; 9 Jan 2002 16:52:55 -0000 Received: (from mec@localhost) by duracef.shout.net (8.8.7/8.8.7) id KAA16574; Wed, 9 Jan 2002 10:52:52 -0600 Date: Wed, 09 Jan 2002 08:53:00 -0000 From: Michael Elizabeth Chastain Message-Id: <200201091652.KAA16574@duracef.shout.net> To: fnf@redhat.com Subject: Re: [RFC] const qualifiers in gdb.c++/method.exp Cc: gdb-patches@sources.redhat.com X-SW-Source: 2002-01/txt/msg00175.txt.bz2 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.