fix PR c++/16117
authorTom Tromey <tromey@redhat.com>
Mon, 4 Nov 2013 19:38:10 +0000 (12:38 -0700)
committerTom Tromey <tromey@redhat.com>
Fri, 15 Nov 2013 15:43:14 +0000 (08:43 -0700)
This patch fixes PR c++/16117.

gdb has an extension so that users can use expressions like FILE::NAME
to choose a variable of the given name from the given file.  The bug
is that this extension takes precedence over ordinary C++ expressions
of the same form.  You might think this is merely hypothetical, but
now that C++ headers commonly do not use an extension, it is more
common.

This patch fixes the bug by making two related changes.  First, it
changes gdb to prefer the ordinary C++ meaning of a symbol over the
extended meaning.  Second, it arranges for single-quoting of the
symbol to indicate a preference for the extension.

Built and regtested on x86-64 Fedora 18.
New test case included.

2013-11-15  Tom Tromey  <tromey@redhat.com>

PR c++/16117:
* c-exp.y (lex_one_token): Add "is_quoted_name" argument.
(classify_name): Likewise.  Prefer a field of "this" over a
filename.
(classify_inner_name, yylex): Update.

2013-11-15  Tom Tromey  <tromey@redhat.com>

* gdb.texinfo (Variables): Note gdb rules for ambiguous cases.
Add example.

2013-11-15  Tom Tromey  <tromey@redhat.com>

* gdb.cp/includefile: New file.
* gdb.cp/filename.exp: New file.
* gdb.cp/filename.cc: New file.

gdb/ChangeLog
gdb/c-exp.y
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.cp/filename.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/filename.exp [new file with mode: 0644]
gdb/testsuite/gdb.cp/includefile [new file with mode: 0644]

index cc9d32dca12ebcc7489a1580ac78612861f464f5..630f86b8e76d216f65e734fb8d958e633f49cffb 100644 (file)
@@ -1,3 +1,11 @@
+2013-11-15  Tom Tromey  <tromey@redhat.com>
+
+       PR c++/16117:
+       * c-exp.y (lex_one_token): Add "is_quoted_name" argument.
+       (classify_name): Likewise.  Prefer a field of "this" over a
+       filename.
+       (classify_inner_name, yylex): Update.
+
 2013-11-15  Joel Brobecker  <brobecker@adacore.com>
 
        * dwarf2expr.h (struct dwarf_expr_context_funcs) <read_reg>:
index 77713dd35f1ed407524eb2c7f8021d208c142987..fecfd152f1dedbdddca2f939f68a5737d6c57d5a 100644 (file)
@@ -2415,7 +2415,7 @@ static int last_was_structop;
 /* Read one token, getting characters through lexptr.  */
 
 static int
-lex_one_token (void)
+lex_one_token (int *is_quoted_name)
 {
   int c;
   int namelen;
@@ -2425,6 +2425,7 @@ lex_one_token (void)
   char *copy;
 
   last_was_structop = 0;
+  *is_quoted_name = 0;
 
  retry:
 
@@ -2669,6 +2670,8 @@ lex_one_token (void)
              {
                ++tokstart;
                namelen = lexptr - tokstart - 1;
+               *is_quoted_name = 1;
+
                goto tryname;
              }
            else if (host_len > 1)
@@ -2813,10 +2816,11 @@ static struct obstack name_obstack;
 
 /* Classify a NAME token.  The contents of the token are in `yylval'.
    Updates yylval and returns the new token type.  BLOCK is the block
-   in which lookups start; this can be NULL to mean the global
-   scope.  */
+   in which lookups start; this can be NULL to mean the global scope.
+   IS_QUOTED_NAME is non-zero if the name token was originally quoted
+   in single quotes.  */
 static int
-classify_name (const struct block *block)
+classify_name (const struct block *block, int is_quoted_name)
 {
   struct symbol *sym;
   char *copy;
@@ -2840,16 +2844,6 @@ classify_name (const struct block *block)
     }
   else if (!sym)
     {
-      /* See if it's a file name. */
-      struct symtab *symtab;
-
-      symtab = lookup_symtab (copy);
-      if (symtab)
-       {
-         yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
-         return FILENAME;
-       }
-
       /* If we found a field of 'this', we might have erroneously
         found a constructor where we wanted a type name.  Handle this
         case by noticing that we found a constructor and then look up
@@ -2869,6 +2863,24 @@ classify_name (const struct block *block)
              return TYPENAME;
            }
        }
+
+      /* If we found a field, then we want to prefer it over a
+        filename.  However, if the name was quoted, then it is better
+        to check for a filename or a block, since this is the only
+        way the user has of requiring the extension to be used.  */
+      if (is_a_field_of_this.type == NULL || is_quoted_name)
+       {
+         /* See if it's a file name. */
+         struct symtab *symtab;
+
+         symtab = lookup_symtab (copy);
+         if (symtab)
+           {
+             yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab),
+                                              STATIC_BLOCK);
+             return FILENAME;
+           }
+       }
     }
 
   if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
@@ -2938,7 +2950,7 @@ classify_inner_name (const struct block *block, struct type *context)
   char *copy;
 
   if (context == NULL)
-    return classify_name (block);
+    return classify_name (block, 0);
 
   type = check_typedef (context);
   if (TYPE_CODE (type) != TYPE_CODE_STRUCT
@@ -2986,6 +2998,7 @@ yylex (void)
   struct type *context_type = NULL;
   int last_to_examine, next_to_examine, checkpoint;
   const struct block *search_block;
+  int is_quoted_name;
 
   if (popping && !VEC_empty (token_and_value, token_fifo))
     goto do_pop;
@@ -2994,9 +3007,9 @@ yylex (void)
   /* Read the first token and decide what to do.  Most of the
      subsequent code is C++-only; but also depends on seeing a "::" or
      name-like token.  */
-  current.token = lex_one_token ();
+  current.token = lex_one_token (&is_quoted_name);
   if (current.token == NAME)
-    current.token = classify_name (expression_context_block);
+    current.token = classify_name (expression_context_block, is_quoted_name);
   if (parse_language->la_language != language_cplus
       || (current.token != TYPENAME && current.token != COLONCOLON
          && current.token != FILENAME))
@@ -3009,7 +3022,11 @@ yylex (void)
   last_was_coloncolon = current.token == COLONCOLON;
   while (1)
     {
-      current.token = lex_one_token ();
+      int ignore;
+
+      /* We ignore quoted names other than the very first one.
+        Subsequent ones do not have any special meaning.  */
+      current.token = lex_one_token (&ignore);
       current.value = yylval;
       VEC_safe_push (token_and_value, token_fifo, &current);
 
index 0dc75cd6948be4ca1074fcb514e0c3f1939d1030..2750b0a1c5998d1d052b203a2c1ba3ca4e89769e 100644 (file)
@@ -1,3 +1,8 @@
+2013-11-15  Tom Tromey  <tromey@redhat.com>
+
+       * gdb.texinfo (Variables): Note gdb rules for ambiguous cases.
+       Add example.
+
 2013-11-14  Tom Tromey  <tromey@redhat.com>
 
        * gdb.texinfo (Breakpoints In Python): Replace "as" with "in".
index c2dfa170ff516c52223b2d982796da531c649501..cfb2cdb3d4da957c2877bc4dd7e209e3e039f2e1 100644 (file)
@@ -8324,11 +8324,24 @@ $4 = 0
 @end smallexample
 
 @cindex C@t{++} scope resolution
-These uses of @samp{::} are very rarely in conflict with the very similar
-use of the same notation in C@t{++}.  @value{GDBN} also supports use of the C@t{++}
-scope resolution operator in @value{GDBN} expressions.
-@c FIXME: Um, so what happens in one of those rare cases where it's in
-@c conflict??  --mew
+These uses of @samp{::} are very rarely in conflict with the very
+similar use of the same notation in C@t{++}.  When they are in
+conflict, the C@t{++} meaning takes precedence; however, this can be
+overridden by quoting the file or function name with single quotes.
+
+For example, suppose the program is stopped in a method of a class
+that has a field named @code{includefile}, and there is also an
+include file named @file{includefile} that defines a variable,
+@code{some_global}.
+
+@smallexample
+(@value{GDBP}) p includefile
+$1 = 23
+(@value{GDBP}) p includefile::some_global
+A syntax error in expression, near `'.
+(@value{GDBP}) p 'includefile'::some_global
+$2 = 27
+@end smallexample
 
 @cindex wrong values
 @cindex variable values, wrong
index 1f7219b465498f04dd3824f6f38160a8b5f7c444..e3ed8788a25944092cc6fca8199990b577a108ca 100644 (file)
@@ -1,3 +1,9 @@
+2013-11-15  Tom Tromey  <tromey@redhat.com>
+
+       * gdb.cp/includefile: New file.
+       * gdb.cp/filename.exp: New file.
+       * gdb.cp/filename.cc: New file.
+
 2013-11-15  Doug Evans  <xdje42@gmail.com>
 
        * gdb.python/py-breakpoint.exp: Make tests have unique names.
diff --git a/gdb/testsuite/gdb.cp/filename.cc b/gdb/testsuite/gdb.cp/filename.cc
new file mode 100644 (file)
index 0000000..716f48b
--- /dev/null
@@ -0,0 +1,36 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "includefile"
+
+class C {
+public:
+  int includefile[1];
+
+  C() {
+    includefile[0] = 23;
+  }
+
+  void m() {
+    /* stop here */
+  }
+};
+
+int main() {
+  C c;
+  c.m();
+}
diff --git a/gdb/testsuite/gdb.cp/filename.exp b/gdb/testsuite/gdb.cp/filename.exp
new file mode 100644 (file)
index 0000000..b908715
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if { [skip_cplus_tests] } { continue }
+
+standard_testfile .cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+if ![runto_main] then {
+    perror "couldn't run to main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "stop here"]
+gdb_continue_to_breakpoint "stop here"
+
+gdb_test "print includefile\[0\]" " = 23"
+gdb_test "print 'includefile'::some_global" " = 27"
diff --git a/gdb/testsuite/gdb.cp/includefile b/gdb/testsuite/gdb.cp/includefile
new file mode 100644 (file)
index 0000000..9dfa787
--- /dev/null
@@ -0,0 +1,18 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int some_global = 27;