public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/9] Further language class related changes
@ 2020-11-20 11:54 Andrew Burgess
  2020-11-20 11:54 ` [PATCH 1/9] gdb: delete unused function print_char_chars Andrew Burgess
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:54 UTC (permalink / raw)
  To: gdb-patches

The changes in this series do two things:

 1. Reduce the use of the LA_* macros from language.h, with
    LA_EMIT_CHAR being completely removed, and LA_PRINT_STRING being
    reduced in usage.

 2. Move some additional language classes into the language's header
    file.  This allows functions defined in different *.c files to be
    renamed as language_class::member_function rather than having to
    trampoline from the member function to a global.

The patch that's most worth reviewing is, I think #2 where I replace
direct calls to a global function with calls to a language classes
member functions.

All feedback welcome.

Thanks,
Andrew


---

Andrew Burgess (9):
  gdb: delete unused function print_char_chars
  gdb: avoid accessing global C++ language implementation functions
  gdb: rename c_printchar as language_defn::printchar
  gdb: remove LA_EMIT_CHAR macro
  gdb: move go_language class declaration into header file
  gdb: move pascal_language into p-lang.h
  gdb/objc: fix bug in objc_language::opcode_print_table
  gdb: move rust_language into rust-lang.h
  gdb: remove some uses of LA_PRINT_STRING

 gdb/ChangeLog                | 162 ++++++++++++++
 gdb/c-lang.c                 |   7 +-
 gdb/c-lang.h                 |   2 -
 gdb/dwarf2/read.c            |   7 +-
 gdb/expprint.c               |  19 +-
 gdb/f-lang.h                 |   2 +-
 gdb/f-valprint.c             |  10 +-
 gdb/go-exp.y                 |   4 +-
 gdb/go-lang.c                | 164 ++++-----------
 gdb/go-lang.h                |  94 +++++++--
 gdb/go-typeprint.c           |   6 +-
 gdb/go-valprint.c            |   5 +-
 gdb/guile/scm-pretty-print.c |   4 +-
 gdb/language.c               |   9 -
 gdb/language.h               |   2 -
 gdb/objc-lang.c              |   2 +-
 gdb/p-exp.y                  |  11 +-
 gdb/p-lang.c                 | 384 ++++++++++++---------------------
 gdb/p-lang.h                 | 245 ++++++++++++++++++---
 gdb/p-typeprint.c            | 214 +++++++------------
 gdb/p-valprint.c             |  30 ++-
 gdb/python/py-prettyprint.c  |   4 +-
 gdb/rust-exp.y               |   2 +-
 gdb/rust-lang.c              | 397 +++++++++++------------------------
 gdb/rust-lang.h              | 198 ++++++++++++++++-
 gdb/symtab.c                 |   3 +-
 gdb/valprint.c               |  37 ----
 gdb/valprint.h               |   3 -
 28 files changed, 1089 insertions(+), 938 deletions(-)

-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/9] gdb: delete unused function print_char_chars
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
@ 2020-11-20 11:54 ` Andrew Burgess
  2020-11-20 11:54 ` [PATCH 2/9] gdb: avoid accessing global C++ language implementation functions Andrew Burgess
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:54 UTC (permalink / raw)
  To: gdb-patches

Spotted that print_char_chars appears to be unused, delete it.  There
should be no user visible changes after this commit.

gdb/ChangeLog:

	* valprint.c (print_char_chars): Delete definition.
	* valprint.h (print_char_chars): Delete declaration.
---
 gdb/ChangeLog  |  5 +++++
 gdb/valprint.c | 37 -------------------------------------
 gdb/valprint.h |  3 ---
 3 files changed, 5 insertions(+), 40 deletions(-)

diff --git a/gdb/valprint.c b/gdb/valprint.c
index 38ae0bdf0e2..46ff931fd3d 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -1827,43 +1827,6 @@ print_hex_chars (struct ui_file *stream, const gdb_byte *valaddr,
     }
 }
 
-/* VALADDR points to a char integer of LEN bytes.
-   Print it out in appropriate language form on stream.
-   Omit any leading zero chars.  */
-
-void
-print_char_chars (struct ui_file *stream, struct type *type,
-		  const gdb_byte *valaddr,
-		  unsigned len, enum bfd_endian byte_order)
-{
-  const gdb_byte *p;
-
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      p = valaddr;
-      while (p < valaddr + len - 1 && *p == 0)
-	++p;
-
-      while (p < valaddr + len)
-	{
-	  LA_EMIT_CHAR (*p, type, stream, '\'');
-	  ++p;
-	}
-    }
-  else
-    {
-      p = valaddr + len - 1;
-      while (p > valaddr && *p == 0)
-	--p;
-
-      while (p >= valaddr)
-	{
-	  LA_EMIT_CHAR (*p, type, stream, '\'');
-	  --p;
-	}
-    }
-}
-
 /* Print function pointer with inferior address ADDRESS onto stdio
    stream STREAM.  */
 
diff --git a/gdb/valprint.h b/gdb/valprint.h
index ef9ebfa84f0..47f6ed009b9 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -157,9 +157,6 @@ extern void print_decimal_chars (struct ui_file *, const gdb_byte *,
 extern void print_hex_chars (struct ui_file *, const gdb_byte *,
 			     unsigned int, enum bfd_endian, bool);
 
-extern void print_char_chars (struct ui_file *, struct type *,
-			      const gdb_byte *, unsigned int, enum bfd_endian);
-
 extern void print_function_pointer_address (const struct value_print_options *options,
 					    struct gdbarch *gdbarch,
 					    CORE_ADDR address,
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 2/9] gdb: avoid accessing global C++ language implementation functions
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
  2020-11-20 11:54 ` [PATCH 1/9] gdb: delete unused function print_char_chars Andrew Burgess
@ 2020-11-20 11:54 ` Andrew Burgess
  2020-12-10 20:47   ` Tom Tromey
  2020-11-20 11:54 ` [PATCH 3/9] gdb: rename c_printchar as language_defn::printchar Andrew Burgess
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:54 UTC (permalink / raw)
  To: gdb-patches

The function c_printchar is called from two places; it provides the
implementation of language_defn::printchar and it is called from
dwarf2_compute_name.

It would be nice to rename c_printchar as language_defn::printchar and
so avoid the trampoline.

To achieve this, instead of calling c_printchar directly from the
DWARF code, I lookup the C++ language object and call the printchar
member function.

In a later commit I can then rename c_printchar.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* dwarf2/read.c (dwarf2_compute_name): Call methods on C++
	language object instead of calling global functions directly.
---
 gdb/ChangeLog     | 5 +++++
 gdb/dwarf2/read.c | 7 ++++---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 3c598262913..b3e51d49584 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -10464,6 +10464,7 @@ dwarf2_compute_name (const char *name,
 	      struct attribute *attr;
 	      struct die_info *child;
 	      int first = 1;
+	      const language_defn *cplus_lang = language_def (cu->language);
 
 	      die->building_fullname = 1;
 
@@ -10498,8 +10499,8 @@ dwarf2_compute_name (const char *name,
 
 		  if (child->tag == DW_TAG_template_type_param)
 		    {
-		      c_print_type (type, "", &buf, -1, 0, cu->language,
-				    &type_print_raw_options);
+		      cplus_lang->print_type (type, "", &buf, -1, 0,
+					      &type_print_raw_options);
 		      continue;
 		    }
 
@@ -10519,7 +10520,7 @@ dwarf2_compute_name (const char *name,
 		  if (type->has_no_signedness ())
 		    /* GDB prints characters as NUMBER 'CHAR'.  If that's
 		       changed, this can use value_print instead.  */
-		    c_printchar (value, type, &buf);
+		    cplus_lang->printchar (value, type, &buf);
 		  else
 		    {
 		      struct value_print_options opts;
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 3/9] gdb: rename c_printchar as language_defn::printchar
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
  2020-11-20 11:54 ` [PATCH 1/9] gdb: delete unused function print_char_chars Andrew Burgess
  2020-11-20 11:54 ` [PATCH 2/9] gdb: avoid accessing global C++ language implementation functions Andrew Burgess
@ 2020-11-20 11:54 ` Andrew Burgess
  2020-11-20 11:54 ` [PATCH 4/9] gdb: remove LA_EMIT_CHAR macro Andrew Burgess
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:54 UTC (permalink / raw)
  To: gdb-patches

This commit removes the global function c_printchar and moves the
implementation into language_defn::printchar.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* c-lang.c (c_printchar): Rename to...
	(language_defn::printchar): ...this.
	* c-lang.h (c_printchar): Delete declaration.
	* language.c (language_defn::printchar): Delete this
	implementation.  Is now implemented in c-lang.c.
---
 gdb/ChangeLog  | 8 ++++++++
 gdb/c-lang.c   | 5 ++++-
 gdb/c-lang.h   | 2 --
 gdb/language.c | 9 ---------
 4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 624aea52f77..5d696b1b356 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -153,8 +153,11 @@ c_emit_char (int c, struct type *type,
   generic_emit_char (c, type, stream, quoter, encoding);
 }
 
+/* See language.h.  */
+
 void
-c_printchar (int c, struct type *type, struct ui_file *stream)
+language_defn::printchar (int c, struct type *type,
+			  struct ui_file * stream) const
 {
   c_string_type str_type;
 
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index 6c5d0d814c4..846faaaaaa2 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -96,8 +96,6 @@ extern struct value *evaluate_subexp_c (struct type *expect_type,
 					int *pos,
 					enum noside noside);
 
-extern void c_printchar (int, struct type *, struct ui_file *);
-
 extern void c_printstr (struct ui_file * stream,
 			struct type *elttype,
 			const gdb_byte *string,
diff --git a/gdb/language.c b/gdb/language.c
index 579cf9198c8..d1bcc738b33 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -677,15 +677,6 @@ language_defn::emitchar (int ch, struct type *chtype,
 
 /* See language.h.  */
 
-void
-language_defn::printchar (int ch, struct type *chtype,
-			  struct ui_file * stream) const
-{
-  c_printchar (ch, chtype, stream);
-}
-
-/* See language.h.  */
-
 void
 language_defn::printstr (struct ui_file *stream, struct type *elttype,
 			 const gdb_byte *string, unsigned int length,
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 4/9] gdb: remove LA_EMIT_CHAR macro
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (2 preceding siblings ...)
  2020-11-20 11:54 ` [PATCH 3/9] gdb: rename c_printchar as language_defn::printchar Andrew Burgess
@ 2020-11-20 11:54 ` Andrew Burgess
  2020-11-20 11:55 ` [PATCH 5/9] gdb: move go_language class declaration into header file Andrew Burgess
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:54 UTC (permalink / raw)
  To: gdb-patches

Now that every use of the LA_EMIT_CHAR macro is within a language_defn
member function we can simply call the emitchar member function
directly instead of using the LA_EMIT_CHAR macro.

If we are ever inside a language object, for example, cplus_language,
while current_language points at something other than cplus_language
then this commit will result in a change in behaviour.  However, I
believe if we did have such a difference then this would be a bug in
GDB.  AS such I'm going to claim there _should_ be no user visible
changes from this commit.

gdb/ChangeLog:

	* c-lang.c (language_defn::printchar): Call emitchar, not
	LA_EMIT_CHAR.
	* f-lang.h (f_language::printchar): Likewise.
	* language.h (LA_EMIT_CHAR): Delete macro.
	* rust-lang.c (rust_language::printchar): Call emitchar, not
	LA_EMIT_CHAR.
---
 gdb/ChangeLog   | 9 +++++++++
 gdb/c-lang.c    | 2 +-
 gdb/f-lang.h    | 2 +-
 gdb/language.h  | 2 --
 gdb/rust-lang.c | 2 +-
 5 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 5d696b1b356..e983804a9f8 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -178,7 +178,7 @@ language_defn::printchar (int c, struct type *type,
     }
 
   fputc_filtered ('\'', stream);
-  LA_EMIT_CHAR (c, type, stream, '\'');
+  emitchar (c, type, stream, '\'');
   fputc_filtered ('\'', stream);
 }
 
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index 351f2191c16..51ee6f67d07 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -155,7 +155,7 @@ class f_language : public language_defn
 		  struct ui_file *stream) const override
   {
     fputs_filtered ("'", stream);
-    LA_EMIT_CHAR (ch, chtype, stream, '\'');
+    emitchar (ch, chtype, stream, '\'');
     fputs_filtered ("'", stream);
   }
 
diff --git a/gdb/language.h b/gdb/language.h
index 1b602646651..815b1923d58 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -768,8 +768,6 @@ extern enum language set_language (enum language);
 #define LA_PRINT_STRING(stream, elttype, string, length, encoding, force_ellipses, options) \
   (current_language->printstr (stream, elttype, string, length, \
 			       encoding, force_ellipses,options))
-#define LA_EMIT_CHAR(ch, type, stream, quoter) \
-  (current_language->emitchar (ch, type, stream, quoter))
 
 /* Test a character to decide whether it can be printed in literal form
    or needs to be printed in another representation.  For example,
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 407be569308..4cfe44a1ad7 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -2069,7 +2069,7 @@ class rust_language : public language_defn
 		  struct ui_file *stream) const override
   {
     fputs_filtered ("'", stream);
-    LA_EMIT_CHAR (ch, chtype, stream, '\'');
+    emitchar (ch, chtype, stream, '\'');
     fputs_filtered ("'", stream);
   }
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 5/9] gdb: move go_language class declaration into header file
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (3 preceding siblings ...)
  2020-11-20 11:54 ` [PATCH 4/9] gdb: remove LA_EMIT_CHAR macro Andrew Burgess
@ 2020-11-20 11:55 ` Andrew Burgess
  2020-11-20 11:55 ` [PATCH 6/9] gdb: move pascal_language into p-lang.h Andrew Burgess
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:55 UTC (permalink / raw)
  To: gdb-patches

Move the go_language class into go-lang.h, this allows us to have
member functions implemented directly in the different go-*.c files
instead of having to trampoline out to global functions.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* go-exp.y (go_parse): Rename to...
	(go_language::parser): ...this.
	* go-lang.c (go_demangle): Rename to...
	(go_language::demangle_symbol): ...this.
	(go_language::expression_ops): Implementation moved here out of
	class declaration.
	(go_op_print_tab): Rename to...
	(go_language::op_print_tab): ...this, update comment.
	(class go_language): Declaration moved to go-lang.h.
	(go_language::language_arch_info): Implementation moved here out
	of class declaration.
	* go-lang.h (go_parse): Delete declaration.
	(go_demangle): Delete declaration.
	(go_print_type): Delete declaration.
	(go_value_print_inner): Delete declaration.
	(class go_language): Declaration moved here from go-lang.c.
	* go-typeprint.c (go_print_type): Rename to...
	(go_language::print_type): ...this.
	* go-valprint.c (go_value_print_inner): Rename to...
	(go_language::value_print_inner): ...this.
	* symtab.c (demangle_for_lookup): Call demangle_symbol method on
	the go_language object.
---
 gdb/ChangeLog      |  25 +++++++
 gdb/go-exp.y       |   4 +-
 gdb/go-lang.c      | 164 +++++++++++++--------------------------------
 gdb/go-lang.h      |  94 ++++++++++++++++++++++----
 gdb/go-typeprint.c |   6 +-
 gdb/go-valprint.c  |   5 +-
 gdb/symtab.c       |   3 +-
 7 files changed, 161 insertions(+), 140 deletions(-)

diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index a9118749097..078bdca732c 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -1550,8 +1550,10 @@ yylex (void)
   return classify_name (pstate, pstate->expression_context_block);
 }
 
+/* See language.h.  */
+
 int
-go_parse (struct parser_state *par_state)
+go_language::parser (struct parser_state *par_state) const
 {
   /* Setting up the parser state.  */
   scoped_restore pstate_restore = make_scoped_restore (&pstate);
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index 4547b52219b..eafcfb4676a 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -334,7 +334,7 @@ unpack_mangled_go_symbol (const char *mangled_name,
    thus not too much effort is currently put into it.  */
 
 char *
-go_demangle (const char *mangled_name, int options)
+go_language::demangle_symbol (const char *mangled_name, int options) const
 {
   struct obstack tempbuf;
   char *result;
@@ -386,6 +386,14 @@ go_demangle (const char *mangled_name, int options)
   return result;
 }
 
+/* See language.h.  */
+
+const struct exp_descriptor *
+go_language::expression_ops () const
+{
+  return &exp_descriptor_c;
+}
+
 /* Given a Go symbol, return its package or NULL if unknown.
    Space for the result is malloc'd, caller must free.  */
 
@@ -444,11 +452,11 @@ go_block_package_name (const struct block *block)
   return NULL;
 }
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.
+/* See go-lang.h.
+
    TODO(dje): &^ ?  */
 
-static const struct op_print go_op_print_tab[] =
+const struct op_print go_language::op_print_tab[] =
 {
   {",", BINOP_COMMA, PREC_COMMA, 0},
   {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
@@ -482,125 +490,43 @@ static const struct op_print go_op_print_tab[] =
   {NULL, OP_NULL, PREC_SUFFIX, 0}
 };
 
-/* Class representing the Go language.  */
+/* See language.h.  */
 
-class go_language : public language_defn
+void
+go_language::language_arch_info (struct gdbarch *gdbarch,
+				 struct language_arch_info *lai) const
 {
-public:
-  go_language ()
-    : language_defn (language_go)
-  { /* Nothing.  */ }
-
-  /* See language.h.  */
-
-  const char *name () const override
-  { return "go"; }
-
-  /* See language.h.  */
-
-  const char *natural_name () const override
-  { return "Go"; }
-
-  /* See language.h.  */
-  void language_arch_info (struct gdbarch *gdbarch,
-			   struct language_arch_info *lai) const override
-  {
-    const struct builtin_go_type *builtin = builtin_go_type (gdbarch);
-
-    /* Helper function to allow shorter lines below.  */
-    auto add  = [&] (struct type * t) -> struct type *
-    {
-      lai->add_primitive_type (t);
-      return t;
-    };
-
-    add (builtin->builtin_void);
-    add (builtin->builtin_char);
-    add (builtin->builtin_bool);
-    add (builtin->builtin_int);
-    add (builtin->builtin_uint);
-    add (builtin->builtin_uintptr);
-    add (builtin->builtin_int8);
-    add (builtin->builtin_int16);
-    add (builtin->builtin_int32);
-    add (builtin->builtin_int64);
-    add (builtin->builtin_uint8);
-    add (builtin->builtin_uint16);
-    add (builtin->builtin_uint32);
-    add (builtin->builtin_uint64);
-    add (builtin->builtin_float32);
-    add (builtin->builtin_float64);
-    add (builtin->builtin_complex64);
-    add (builtin->builtin_complex128);
-
-    lai->set_string_char_type (builtin->builtin_char);
-    lai->set_bool_type (builtin->builtin_bool, "bool");
-  }
-
-  /* See language.h.  */
-  bool sniff_from_mangled_name (const char *mangled,
-				char **demangled) const override
-  {
-    *demangled = go_demangle (mangled, 0);
-    return *demangled != NULL;
-  }
-
-  /* See language.h.  */
-
-  char *demangle_symbol (const char *mangled, int options) const override
-  {
-    return go_demangle (mangled, options);
-  }
+  const struct builtin_go_type *builtin = builtin_go_type (gdbarch);
 
-  /* See language.h.  */
-
-  void print_type (struct type *type, const char *varstring,
-		   struct ui_file *stream, int show, int level,
-		   const struct type_print_options *flags) const override
-  {
-    go_print_type (type, varstring, stream, show, level, flags);
-  }
-
-  /* See language.h.  */
-
-  void value_print_inner
-	(struct value *val, struct ui_file *stream, int recurse,
-	 const struct value_print_options *options) const override
-  {
-    return go_value_print_inner (val, stream, recurse, options);
-  }
-
-  /* See language.h.  */
-
-  int parser (struct parser_state *ps) const override
-  {
-    return go_parse (ps);
-  }
-
-  /* See language.h.  */
-
-  bool is_string_type_p (struct type *type) const override
+  /* Helper function to allow shorter lines below.  */
+  auto add  = [&] (struct type * t) -> struct type *
   {
-    type = check_typedef (type);
-    return (type->code () == TYPE_CODE_STRUCT
-	    && go_classify_struct_type (type) == GO_TYPE_STRING);
-  }
-
-  /* See language.h.  */
-
-  bool store_sym_names_in_linkage_form_p () const override
-  { return true; }
-
-  /* See language.h.  */
-
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return go_op_print_tab; }
-};
+    lai->add_primitive_type (t);
+    return t;
+  };
+
+  add (builtin->builtin_void);
+  add (builtin->builtin_char);
+  add (builtin->builtin_bool);
+  add (builtin->builtin_int);
+  add (builtin->builtin_uint);
+  add (builtin->builtin_uintptr);
+  add (builtin->builtin_int8);
+  add (builtin->builtin_int16);
+  add (builtin->builtin_int32);
+  add (builtin->builtin_int64);
+  add (builtin->builtin_uint8);
+  add (builtin->builtin_uint16);
+  add (builtin->builtin_uint32);
+  add (builtin->builtin_uint64);
+  add (builtin->builtin_float32);
+  add (builtin->builtin_float64);
+  add (builtin->builtin_complex64);
+  add (builtin->builtin_complex128);
+
+  lai->set_string_char_type (builtin->builtin_char);
+  lai->set_bool_type (builtin->builtin_bool, "bool");
+}
 
 /* Single instance of the Go language class.  */
 
diff --git a/gdb/go-lang.h b/gdb/go-lang.h
index 1f079071995..532b4eb0887 100644
--- a/gdb/go-lang.h
+++ b/gdb/go-lang.h
@@ -56,34 +56,100 @@ enum go_type
   GO_TYPE_STRING
 };
 
-/* Defined in go-exp.y.  */
-
-extern int go_parse (struct parser_state *);
-
 /* Defined in go-lang.c.  */
 
 extern const char *go_main_name (void);
 
 extern enum go_type go_classify_struct_type (struct type *type);
 
-extern char *go_demangle (const char *mangled, int options);
-
 extern char *go_symbol_package_name (const struct symbol *sym);
 
 extern char *go_block_package_name (const struct block *block);
 
 extern const struct builtin_go_type *builtin_go_type (struct gdbarch *);
 
-/* Defined in go-typeprint.c.  */
+/* Class representing the Go language.  */
+
+class go_language : public language_defn
+{
+public:
+  go_language ()
+    : language_defn (language_go)
+  { /* Nothing.  */ }
+
+  /* See language.h.  */
+
+  const char *name () const override
+  { return "go"; }
+
+  /* See language.h.  */
+
+  const char *natural_name () const override
+  { return "Go"; }
+
+  /* See language.h.  */
+
+  void language_arch_info (struct gdbarch *gdbarch,
+			   struct language_arch_info *lai) const override;
+
+  /* See language.h.  */
+
+  bool sniff_from_mangled_name (const char *mangled,
+				char **demangled) const override
+  {
+    *demangled = demangle_symbol (mangled, 0);
+    return *demangled != NULL;
+  }
+
+  /* See language.h.  */
+
+  char *demangle_symbol (const char *mangled, int options) const override;
+
+  /* See language.h.  */
 
-extern void go_print_type (struct type *type, const char *varstring,
-			   struct ui_file *stream, int show, int level,
-			   const struct type_print_options *flags);
+  void print_type (struct type *type, const char *varstring,
+		   struct ui_file *stream, int show, int level,
+		   const struct type_print_options *flags) const override;
 
-/* Implement la_value_print_inner for Go.  */
+  /* See language.h.  */
 
-extern void go_value_print_inner (struct value *value,
-				  struct ui_file *stream, int recurse,
-				  const struct value_print_options *options);
+  void value_print_inner
+	(struct value *val, struct ui_file *stream, int recurse,
+	 const struct value_print_options *options) const override;
+
+  /* See language.h.  */
+
+  int parser (struct parser_state *ps) const override;
+
+  /* See language.h.  */
+
+  bool is_string_type_p (struct type *type) const override
+  {
+    type = check_typedef (type);
+    return (type->code () == TYPE_CODE_STRUCT
+	    && go_classify_struct_type (type) == GO_TYPE_STRING);
+  }
+
+  /* See language.h.  */
+
+  bool store_sym_names_in_linkage_form_p () const override
+  { return true; }
+
+  /* See language.h.  */
+
+  const struct exp_descriptor *expression_ops () const override;
+
+  /* See language.h.  */
+
+  const struct op_print *opcode_print_table () const override
+  { return op_print_tab; }
+
+private:
+
+  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
+
+  static const struct op_print op_print_tab[];
+
+};
 
 #endif /* !defined (GO_LANG_H) */
diff --git a/gdb/go-typeprint.c b/gdb/go-typeprint.c
index c334914398d..d768498e639 100644
--- a/gdb/go-typeprint.c
+++ b/gdb/go-typeprint.c
@@ -42,9 +42,9 @@
    LEVEL indicates level of recursion (for nested definitions).  */
 
 void
-go_print_type (struct type *type, const char *varstring,
-	       struct ui_file *stream, int show, int level,
-	       const struct type_print_options *flags)
+go_language::print_type (struct type *type, const char *varstring,
+			 struct ui_file *stream, int show, int level,
+			 const struct type_print_options *flags) const
 {
   /* Borrowed from c-typeprint.c.  */
   if (show > 0)
diff --git a/gdb/go-valprint.c b/gdb/go-valprint.c
index df0c029785d..fdbc5c4e95a 100644
--- a/gdb/go-valprint.c
+++ b/gdb/go-valprint.c
@@ -87,8 +87,9 @@ print_go_string (struct type *type,
 /* See go-lang.h.  */
 
 void
-go_value_print_inner (struct value *val, struct ui_file *stream,
-		      int recurse, const struct value_print_options *options)
+go_language::value_print_inner (struct value *val, struct ui_file *stream,
+				int recurse,
+				const struct value_print_options *options) const
 {
   struct type *type = check_typedef (value_type (val));
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index dccc3d1e237..d068e798edf 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -1842,7 +1842,8 @@ demangle_for_lookup (const char *name, enum language lang,
     }
   else if (lang == language_go)
     {
-      char *demangled_name = go_demangle (name, 0);
+      char *demangled_name
+	= language_def (language_go)->demangle_symbol (name, 0);
       if (demangled_name != NULL)
 	return storage.set_malloc_ptr (demangled_name);
     }
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 6/9] gdb: move pascal_language into p-lang.h
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (4 preceding siblings ...)
  2020-11-20 11:55 ` [PATCH 5/9] gdb: move go_language class declaration into header file Andrew Burgess
@ 2020-11-20 11:55 ` Andrew Burgess
  2020-11-20 11:55 ` [PATCH 7/9] gdb/objc: fix bug in objc_language::opcode_print_table Andrew Burgess
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:55 UTC (permalink / raw)
  To: gdb-patches

Move the pascal_language class declaration into the p-lang.h header
file.  This allows for the function implementations to be spread over
the different p-*.c files without the need for global trampoline
functions.

As a consequence of this change many of the Pascal value and type
printing helper functions have become member functions within the
pascal_language class.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* p-exp.y (exp): Update call to pascal_is_string_type.
	(pascal_parse): Rename to...
	(pascal_language::parser): ...this.
	* p-lang.c (is_pascal_string_type): Rename to...
	(pascal_is_string_type): ...this.
	(pascal_one_char): Rename to...
	(pascal_language::print_one_char): ...this.
	(pascal_printchar): Rename to...
	(pascal_language::printchar): ...this.  Update call to
	print_one_char member function.
	(pascal_op_print_tab): Rename to...
	(pascal_language::op_print_tab): ...this.
	(class pascal_language): Moved to p-lang.h.
	(pascal_language::language_arch_info): Function implementation
	moved out of class declaration.
	(pascal_language::printstr): Likewise.
	* p-lang.h (pascal_parse): Delete declaration.
	(pascal_is_string_type): Declare.
	(pascal_print_type): Delete declaration.
	(pascal_print_typedef): Delete declaration.
	(pascal_value_print_inner): Delete declaration.
	(pascal_value_print): Delete declaration.
	(pascal_type_print_method_args): Delete declaration.
	(is_pascal_string_type): Delete declaration.
	(pascal_printchar): Delete declaration.
	(pascal_builtin_types): Delete declaration.
	(pascal_type_print_base): Delete declaration.
	(pascal_type_print_varspec_prefix): Delete declaration.
	(class pascal_language): Moved here from p-lang.c.
	* p-typeprint.c (pascal_type_print_varspec_suffix): Delete
	declaration.
	(pascal_type_print_derivation_info): Delete declaration.
	(pascal_print_type): Rename to...
	(pascal_language::print_type): ...this.  Update calls to member
	functions.
	(pascal_print_typedef): Rename to...
	(pascal_language::print_typedef): ...this.  Update calls to member
	functions.
	(pascal_type_print_derivation_info): Rename to...
	(pascal_language::type_print_derivation_info): ...this.
	(pascal_type_print_method_args): Rename to...
	(pascal_language::type_print_method_args): ...this.
	(pascal_type_print_varspec_prefix): Rename to...
	(pascal_language::type_print_varspec_prefix): ...this.  Update
	calls to member functions.
	(pascal_print_func_args): Rename to...
	(pascal_language::print_func_args): ...this.  Update calls to
	member functions.
	(pascal_type_print_func_varspec_suffix): Rename to...
	(pascal_language::type_print_func_varspec_suffix): ...this.
	Update calls to member functions.
	(pascal_type_print_varspec_suffix): Rename to...
	(pascal_language::type_print_varspec_suffix): ...this.  Update
	calls to member functions.
	(pascal_type_print_base): Rename to...
	(pascal_language::type_print_base): ...this.  Update calls to
	member functions.
	* p-valprint.c (pascal_value_print_inner): Rename to...
	(pascal_language::value_print_inner): ...this.  Update calls to
	member functions.
	(pascal_value_print): Rename to...
	(pascal_language::value_print): ...this.  Update calls to member
	functions.
---
 gdb/ChangeLog     |  66 ++++++++
 gdb/p-exp.y       |  11 +-
 gdb/p-lang.c      | 384 ++++++++++++++++------------------------------
 gdb/p-lang.h      | 245 +++++++++++++++++++++++++----
 gdb/p-typeprint.c | 214 +++++++++-----------------
 gdb/p-valprint.c  |  22 ++-
 6 files changed, 506 insertions(+), 436 deletions(-)

diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 9caf15f69f5..19ba6e9a5f5 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -303,10 +303,9 @@ exp	:	field_exp COMPLETE
 exp	:	exp '['
 			/* We need to save the current_type value.  */
 			{ const char *arrayname;
-			  int arrayfieldindex;
-			  arrayfieldindex = is_pascal_string_type (
-				current_type, NULL, NULL,
-				NULL, NULL, &arrayname);
+			  int arrayfieldindex
+			    = pascal_is_string_type (current_type, NULL, NULL,
+						     NULL, NULL, &arrayname);
 			  if (arrayfieldindex)
 			    {
 			      struct stoken stringsval;
@@ -1729,8 +1728,10 @@ yylex (void)
   }
 }
 
+/* See language.h.  */
+
 int
-pascal_parse (struct parser_state *par_state)
+pascal_language::parser (struct parser_state *par_state) const
 {
   /* Setting up the parser state.  */
   scoped_restore pstate_restore = make_scoped_restore (&pstate);
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 1610c0accae..3e58cccc006 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -84,20 +84,11 @@ pascal_main_name (void)
   return NULL;
 }
 
-/* Determines if type TYPE is a pascal string type.
-   Returns a positive value if the type is a known pascal string type.
-   This function is used by p-valprint.c code to allow better string display.
-   If it is a pascal string type, then it also sets info needed
-   to get the length and the data of the string
-   length_pos, length_size and string_pos are given in bytes.
-   char_size gives the element size in bytes.
-   FIXME: if the position or the size of these fields
-   are not multiple of TARGET_CHAR_BIT then the results are wrong
-   but this does not happen for Free Pascal nor for GPC.  */
+/* See p-lang.h.  */
+
 int
-is_pascal_string_type (struct type *type,int *length_pos,
-		       int *length_size, int *string_pos,
-		       struct type **char_type,
+pascal_is_string_type (struct type *type,int *length_pos, int *length_size,
+		       int *string_pos, struct type **char_type,
 		       const char **arrayname)
 {
   if (type != NULL && type->code () == TYPE_CODE_STRUCT)
@@ -152,14 +143,11 @@ is_pascal_string_type (struct type *type,int *length_pos,
   return 0;
 }
 
-static void pascal_one_char (int, struct ui_file *, int *);
-
-/* Print the character C on STREAM as part of the contents of a literal
-   string.
-   In_quotes is reset to 0 if a char is written with #4 notation.  */
+/* See p-lang.h.  */
 
-static void
-pascal_one_char (int c, struct ui_file *stream, int *in_quotes)
+void
+pascal_language::print_one_char (int c, struct ui_file *stream,
+				 int *in_quotes) const
 {
   if (c == '\'' || ((unsigned int) c <= 0xff && (PRINT_LITERAL_FORM (c))))
     {
@@ -182,12 +170,15 @@ pascal_one_char (int c, struct ui_file *stream, int *in_quotes)
     }
 }
 
+/* See language.h.  */
+
 void
-pascal_printchar (int c, struct type *type, struct ui_file *stream)
+pascal_language::printchar (int c, struct type *type,
+			    struct ui_file *stream) const
 {
   int in_quotes = 0;
 
-  pascal_one_char (c, stream, &in_quotes);
+  print_one_char (c, stream, &in_quotes);
   if (in_quotes)
     fputs_filtered ("'", stream);
 }
@@ -197,7 +188,7 @@ pascal_printchar (int c, struct type *type, struct ui_file *stream)
 /* Table mapping opcodes into strings for printing operators
    and precedences of the operators.  */
 
-const struct op_print pascal_op_print_tab[] =
+const struct op_print pascal_language::op_print_tab[] =
 {
   {",", BINOP_COMMA, PREC_COMMA, 0},
   {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
@@ -228,249 +219,138 @@ const struct op_print pascal_op_print_tab[] =
 };
 \f
 
-/* Class representing the Pascal language.  */
+/* See language.h.  */
 
-class pascal_language : public language_defn
+void pascal_language::language_arch_info
+	(struct gdbarch *gdbarch, struct language_arch_info *lai) const
 {
-public:
-  pascal_language ()
-    : language_defn (language_pascal)
-  { /* Nothing.  */ }
-
-  /* See language.h.  */
-
-  const char *name () const override
-  { return "pascal"; }
-
-  /* See language.h.  */
-
-  const char *natural_name () const override
-  { return "Pascal"; }
-
-  /* See language.h.  */
-
-  const std::vector<const char *> &filename_extensions () const override
-  {
-    static const std::vector<const char *> extensions
-      = { ".pas", ".p", ".pp" };
-    return extensions;
-  }
-
-  /* See language.h.  */
-  void language_arch_info (struct gdbarch *gdbarch,
-			   struct language_arch_info *lai) const override
-  {
-    const struct builtin_type *builtin = builtin_type (gdbarch);
-
-    /* Helper function to allow shorter lines below.  */
-    auto add  = [&] (struct type * t)
-    {
-      lai->add_primitive_type (t);
-    };
-
-    add (builtin->builtin_int);
-    add (builtin->builtin_long);
-    add (builtin->builtin_short);
-    add (builtin->builtin_char);
-    add (builtin->builtin_float);
-    add (builtin->builtin_double);
-    add (builtin->builtin_void);
-    add (builtin->builtin_long_long);
-    add (builtin->builtin_signed_char);
-    add (builtin->builtin_unsigned_char);
-    add (builtin->builtin_unsigned_short);
-    add (builtin->builtin_unsigned_int);
-    add (builtin->builtin_unsigned_long);
-    add (builtin->builtin_unsigned_long_long);
-    add (builtin->builtin_long_double);
-    add (builtin->builtin_complex);
-    add (builtin->builtin_double_complex);
-
-    lai->set_string_char_type (builtin->builtin_char);
-    lai->set_bool_type (builtin->builtin_bool, "boolean");
-  }
-
-  /* See language.h.  */
-
-  void print_type (struct type *type, const char *varstring,
-		   struct ui_file *stream, int show, int level,
-		   const struct type_print_options *flags) const override
-  {
-    pascal_print_type (type, varstring, stream, show, level, flags);
-  }
-
-  /* See language.h.  */
-
-  void value_print (struct value *val, struct ui_file *stream,
-		    const struct value_print_options *options) const override
-  {
-    return pascal_value_print (val, stream, options);
-  }
-
-  /* See language.h.  */
-
-  void value_print_inner
-	(struct value *val, struct ui_file *stream, int recurse,
-	 const struct value_print_options *options) const override
-  {
-    return pascal_value_print_inner (val, stream, recurse, options);
-  }
-
-  /* See language.h.  */
-
-  int parser (struct parser_state *ps) const override
-  {
-    return pascal_parse (ps);
-  }
-
-  /* See language.h.  */
-
-  void emitchar (int ch, struct type *chtype,
-		 struct ui_file *stream, int quoter) const override
-  {
-    int in_quotes = 0;
-
-    pascal_one_char (ch, stream, &in_quotes);
-    if (in_quotes)
-      fputs_filtered ("'", stream);
-  }
-
-  /* See language.h.  */
+  const struct builtin_type *builtin = builtin_type (gdbarch);
 
-  void printchar (int ch, struct type *chtype,
-		  struct ui_file *stream) const override
+  /* Helper function to allow shorter lines below.  */
+  auto add  = [&] (struct type * t)
   {
-    pascal_printchar (ch, chtype, stream);
-  }
+    lai->add_primitive_type (t);
+  };
+
+  add (builtin->builtin_int);
+  add (builtin->builtin_long);
+  add (builtin->builtin_short);
+  add (builtin->builtin_char);
+  add (builtin->builtin_float);
+  add (builtin->builtin_double);
+  add (builtin->builtin_void);
+  add (builtin->builtin_long_long);
+  add (builtin->builtin_signed_char);
+  add (builtin->builtin_unsigned_char);
+  add (builtin->builtin_unsigned_short);
+  add (builtin->builtin_unsigned_int);
+  add (builtin->builtin_unsigned_long);
+  add (builtin->builtin_unsigned_long_long);
+  add (builtin->builtin_long_double);
+  add (builtin->builtin_complex);
+  add (builtin->builtin_double_complex);
+
+  lai->set_string_char_type (builtin->builtin_char);
+  lai->set_bool_type (builtin->builtin_bool, "boolean");
+}
 
-  /* See language.h.  */
+/* See language.h.  */
 
-  void printstr (struct ui_file *stream, struct type *elttype,
-		 const gdb_byte *string, unsigned int length,
-		 const char *encoding, int force_ellipses,
-		 const struct value_print_options *options) const override
-  {
-    enum bfd_endian byte_order = type_byte_order (elttype);
-    unsigned int i;
-    unsigned int things_printed = 0;
-    int in_quotes = 0;
-    int need_comma = 0;
-    int width;
-
-    /* Preserve ELTTYPE's original type, just set its LENGTH.  */
-    check_typedef (elttype);
-    width = TYPE_LENGTH (elttype);
-
-    /* If the string was not truncated due to `set print elements', and
-       the last byte of it is a null, we don't print that, in traditional C
-       style.  */
-    if ((!force_ellipses) && length > 0
-	&& extract_unsigned_integer (string + (length - 1) * width, width,
-				     byte_order) == 0)
-      length--;
-
-    if (length == 0)
-      {
-	fputs_filtered ("''", stream);
-	return;
-      }
-
-    for (i = 0; i < length && things_printed < options->print_max; ++i)
-      {
-	/* Position of the character we are examining
-	   to see whether it is repeated.  */
-	unsigned int rep1;
-	/* Number of repetitions we have detected so far.  */
-	unsigned int reps;
-	unsigned long int current_char;
-
-	QUIT;
-
-	if (need_comma)
-	  {
-	    fputs_filtered (", ", stream);
-	    need_comma = 0;
-	  }
-
-	current_char = extract_unsigned_integer (string + i * width, width,
-						 byte_order);
-
-	rep1 = i + 1;
-	reps = 1;
-	while (rep1 < length
-	       && extract_unsigned_integer (string + rep1 * width, width,
-					    byte_order) == current_char)
-	  {
-	    ++rep1;
-	    ++reps;
-	  }
-
-	if (reps > options->repeat_count_threshold)
-	  {
-	    if (in_quotes)
-	      {
-		fputs_filtered ("', ", stream);
-		in_quotes = 0;
-	      }
-	    pascal_printchar (current_char, elttype, stream);
-	    fprintf_filtered (stream, " %p[<repeats %u times>%p]",
-			      metadata_style.style ().ptr (),
-			      reps, nullptr);
-	    i = rep1 - 1;
-	    things_printed += options->repeat_count_threshold;
-	    need_comma = 1;
-	  }
-	else
-	  {
-	    if ((!in_quotes) && (PRINT_LITERAL_FORM (current_char)))
-	      {
-		fputs_filtered ("'", stream);
-		in_quotes = 1;
-	      }
-	    pascal_one_char (current_char, stream, &in_quotes);
-	    ++things_printed;
-	  }
-      }
-
-    /* Terminate the quotes if necessary.  */
-    if (in_quotes)
-      fputs_filtered ("'", stream);
-
-    if (force_ellipses || i < length)
-      fputs_filtered ("...", stream);
-  }
-
-  /* See language.h.  */
-
-  void print_typedef (struct type *type, struct symbol *new_symbol,
-		      struct ui_file *stream) const override
-  {
-    pascal_print_typedef (type, new_symbol, stream);
-  }
+void
+pascal_language::printstr (struct ui_file *stream, struct type *elttype,
+			   const gdb_byte *string, unsigned int length,
+			   const char *encoding, int force_ellipses,
+			   const struct value_print_options *options) const
+{
+  enum bfd_endian byte_order = type_byte_order (elttype);
+  unsigned int i;
+  unsigned int things_printed = 0;
+  int in_quotes = 0;
+  int need_comma = 0;
+  int width;
+
+  /* Preserve ELTTYPE's original type, just set its LENGTH.  */
+  check_typedef (elttype);
+  width = TYPE_LENGTH (elttype);
+
+  /* If the string was not truncated due to `set print elements', and
+     the last byte of it is a null, we don't print that, in traditional C
+     style.  */
+  if ((!force_ellipses) && length > 0
+      && extract_unsigned_integer (string + (length - 1) * width, width,
+				   byte_order) == 0)
+    length--;
+
+  if (length == 0)
+    {
+      fputs_filtered ("''", stream);
+      return;
+    }
 
-  /* See language.h.  */
+  for (i = 0; i < length && things_printed < options->print_max; ++i)
+    {
+      /* Position of the character we are examining
+	 to see whether it is repeated.  */
+      unsigned int rep1;
+      /* Number of repetitions we have detected so far.  */
+      unsigned int reps;
+      unsigned long int current_char;
 
-  bool is_string_type_p (struct type *type) const override
-  {
-    return is_pascal_string_type (type, nullptr, nullptr, nullptr,
-				  nullptr, nullptr) > 0;
-  }
+      QUIT;
 
-  /* See language.h.  */
+      if (need_comma)
+	{
+	  fputs_filtered (", ", stream);
+	  need_comma = 0;
+	}
 
-  const char *name_of_this () const override
-  { return "this"; }
+      current_char = extract_unsigned_integer (string + i * width, width,
+					       byte_order);
 
-  /* See language.h.  */
+      rep1 = i + 1;
+      reps = 1;
+      while (rep1 < length
+	     && extract_unsigned_integer (string + rep1 * width, width,
+					  byte_order) == current_char)
+	{
+	  ++rep1;
+	  ++reps;
+	}
 
-  bool range_checking_on_by_default () const override
-  { return true; }
+      if (reps > options->repeat_count_threshold)
+	{
+	  if (in_quotes)
+	    {
+	      fputs_filtered ("', ", stream);
+	      in_quotes = 0;
+	    }
+	  printchar (current_char, elttype, stream);
+	  fprintf_filtered (stream, " %p[<repeats %u times>%p]",
+			    metadata_style.style ().ptr (),
+			    reps, nullptr);
+	  i = rep1 - 1;
+	  things_printed += options->repeat_count_threshold;
+	  need_comma = 1;
+	}
+      else
+	{
+	  if ((!in_quotes) && (PRINT_LITERAL_FORM (current_char)))
+	    {
+	      fputs_filtered ("'", stream);
+	      in_quotes = 1;
+	    }
+	  print_one_char (current_char, stream, &in_quotes);
+	  ++things_printed;
+	}
+    }
 
-  /* See language.h.  */
+  /* Terminate the quotes if necessary.  */
+  if (in_quotes)
+    fputs_filtered ("'", stream);
 
-  const struct op_print *opcode_print_table () const override
-  { return pascal_op_print_tab; }
-};
+  if (force_ellipses || i < length)
+    fputs_filtered ("...", stream);
+}
 
 /* Single instance of the Pascal language class.  */
 
diff --git a/gdb/p-lang.h b/gdb/p-lang.h
index 3eaad015a6e..3f08a26d2b3 100644
--- a/gdb/p-lang.h
+++ b/gdb/p-lang.h
@@ -25,51 +25,240 @@
 struct value;
 struct parser_state;
 
+/* Determines if type TYPE is a pascal string type.  Returns a positive
+   value if the type is a known pascal string type.  This function is used
+   by p-valprint.c code to allow better string display.  If it is a pascal
+   string type, then it also sets info needed to get the length and the
+   data of the string length_pos, length_size and string_pos are given in
+   bytes.  char_size gives the element size in bytes.  FIXME: if the
+   position or the size of these fields are not multiple of TARGET_CHAR_BIT
+   then the results are wrong but this does not happen for Free Pascal nor
+   for GPC.  */
+
+extern int pascal_is_string_type (struct type *type,int *length_pos,
+				  int *length_size, int *string_pos,
+				  struct type **char_type,
+				  const char **arrayname);
+
 /* Defined in p-lang.c */
+
 extern const char *pascal_main_name (void);
 
-extern int pascal_parse (struct parser_state *); /* Defined in p-exp.y */
+/* These are in p-lang.c: */
 
-/* Defined in p-typeprint.c */
-extern void pascal_print_type (struct type *, const char *, struct ui_file *,
-			       int, int, const struct type_print_options *);
+extern int is_pascal_string_type (struct type *, int *, int *, int *,
+				  struct type **, const char **);
 
-extern void pascal_print_typedef (struct type *, struct symbol *,
-				  struct ui_file *);
+extern int pascal_object_is_vtbl_ptr_type (struct type *);
 
-/* Implement la_value_print_inner for Pascal.  */
+extern int pascal_object_is_vtbl_member (struct type *);
 
-extern void pascal_value_print_inner (struct value *, struct ui_file *, int,
-				      const struct value_print_options *);
+/* Class representing the Pascal language.  */
 
-extern void pascal_value_print (struct value *, struct ui_file *,
-				const struct value_print_options *);
+class pascal_language : public language_defn
+{
+public:
+  pascal_language ()
+    : language_defn (language_pascal)
+  { /* Nothing.  */ }
 
-extern void pascal_type_print_method_args (const char *, const char *,
-					   struct ui_file *);
+  /* See language.h.  */
 
-/* These are in p-lang.c: */
+  const char *name () const override
+  { return "pascal"; }
 
-extern int
-  is_pascal_string_type (struct type *, int *, int *, int *,
-			 struct type **, const char **);
+  /* See language.h.  */
 
-extern void pascal_printchar (int, struct type *, struct ui_file *);
+  const char *natural_name () const override
+  { return "Pascal"; }
 
-extern struct type **const pascal_builtin_types[];
+  /* See language.h.  */
 
-/* These are in p-typeprint.c: */
+  const std::vector<const char *> &filename_extensions () const override
+  {
+    static const std::vector<const char *> extensions
+      = { ".pas", ".p", ".pp" };
+    return extensions;
+  }
 
-extern void
-  pascal_type_print_base (struct type *, struct ui_file *, int, int,
-			  const struct type_print_options *);
+  /* See language.h.  */
 
-extern void
-  pascal_type_print_varspec_prefix (struct type *, struct ui_file *, int, int,
-				    const struct type_print_options *);
+  void language_arch_info (struct gdbarch *gdbarch,
+			   struct language_arch_info *lai) const override;
 
-extern int pascal_object_is_vtbl_ptr_type (struct type *);
+  /* See language.h.  */
 
-extern int pascal_object_is_vtbl_member (struct type *);
+  void print_type (struct type *type, const char *varstring,
+		   struct ui_file *stream, int show, int level,
+		   const struct type_print_options *flags) const override;
+
+  /* See language.h.  */
+
+  void value_print (struct value *val, struct ui_file *stream,
+		    const struct value_print_options *options) const override;
+
+  /* See language.h.  */
+
+  void value_print_inner
+	(struct value *val, struct ui_file *stream, int recurse,
+	 const struct value_print_options *options) const override;
+
+  /* See language.h.  */
+
+  int parser (struct parser_state *ps) const override;
+
+  /* See language.h.  */
+
+  void emitchar (int ch, struct type *chtype,
+		 struct ui_file *stream, int quoter) const override
+  {
+    int in_quotes = 0;
+
+    print_one_char (ch, stream, &in_quotes);
+    if (in_quotes)
+      fputs_filtered ("'", stream);
+  }
+
+  /* See language.h.  */
+
+  void printchar (int ch, struct type *chtype,
+		  struct ui_file *stream) const override;
+
+  /* See language.h.  */
+
+  void printstr (struct ui_file *stream, struct type *elttype,
+		 const gdb_byte *string, unsigned int length,
+		 const char *encoding, int force_ellipses,
+		 const struct value_print_options *options) const override;
+
+  /* See language.h.  */
+
+  void print_typedef (struct type *type, struct symbol *new_symbol,
+		      struct ui_file *stream) const override;
+
+  /* See language.h.  */
+
+  bool is_string_type_p (struct type *type) const override
+  {
+    return pascal_is_string_type(type, nullptr, nullptr, nullptr,
+				 nullptr, nullptr) > 0;
+  }
+
+  /* See language.h.  */
+
+  const char *name_of_this () const override
+  { return "this"; }
+
+  /* See language.h.  */
+
+  bool range_checking_on_by_default () const override
+  { return true; }
+
+  /* See language.h.  */
+
+  const struct op_print *opcode_print_table () const override
+  { return op_print_tab; }
+
+private:
+
+  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
+
+  static const struct op_print op_print_tab[];
+
+  /* Print the character C on STREAM as part of the contents of a literal
+     string.  IN_QUOTES is reset to 0 if a char is written with #4 notation.  */
+
+  void print_one_char (int c, struct ui_file *stream, int *in_quotes) const;
+
+  /* Print the name of the type (or the ultimate pointer target,
+     function value or array element), or the description of a
+     structure or union.
+
+     SHOW positive means print details about the type (e.g. enum values),
+     and print structure elements passing SHOW - 1 for show.  SHOW negative
+     means just print the type name or struct tag if there is one.  If
+     there is no name, print something sensible but concise like "struct
+     {...}".
+     SHOW zero means just print the type name or struct tag if there is one.
+     If there is no name, print something sensible but not as concise like
+     "struct {int x; int y;}".
+
+     LEVEL is the number of spaces to indent by.
+     We increase it for some recursive calls.  */
+
+  void type_print_base (struct type *type, struct ui_file *stream, int show,
+			int level,
+			const struct type_print_options *flags) const;
+
+
+  /* Print any array sizes, function arguments or close parentheses
+     needed after the variable name (to describe its type).
+     Args work like pascal_type_print_varspec_prefix.  */
+
+  void type_print_varspec_suffix (struct type *type, struct ui_file *stream,
+				  int show, int passed_a_ptr,
+				  int demangled_args,
+				  const struct type_print_options *flags) const;
+
+  /* Helper for pascal_language::type_print_varspec_suffix to print the
+     suffix of a function or method.  */
+
+  void type_print_func_varspec_suffix
+	(struct type *type, struct ui_file *stream, int show,
+	 int passed_a_ptr, int demangled_args,
+	 const struct type_print_options *flags) const;
+
+  /* Print any asterisks or open-parentheses needed before the
+     variable name (to describe its type).
+
+     On outermost call, pass 0 for PASSED_A_PTR.
+     On outermost call, SHOW > 0 means should ignore
+     any typename for TYPE and show its details.
+     SHOW is always zero on recursive calls.  */
+
+  void type_print_varspec_prefix
+	(struct type *type, struct ui_file *stream, int show,
+	 int passed_a_ptr, const struct type_print_options *flags) const;
+
+  /* Print the function args from TYPE (a TYPE_CODE_FUNC) to STREAM taking
+     FLAGS into account where appropriate.  */
+
+  void  print_func_args (struct type *type, struct ui_file *stream,
+			 const struct type_print_options *flags) const;
+
+  /* Print the Pascal method arguments for PHYSNAME and METHODNAME to the
+     file STREAM.  */
+
+  void type_print_method_args (const char *physname, const char *methodname,
+			       struct ui_file *stream) const;
+
+  /* If TYPE is a derived type, then print out derivation information.
+     Print only the actual base classes of this type, not the base classes
+     of the base classes.  I.e. for the derivation hierarchy:
+
+     class A { int a; };
+     class B : public A {int b; };
+     class C : public B {int c; };
+
+     Print the type of class C as:
+
+     class C : public B {
+     int c;
+     }
+
+     Not as the following (like gdb used to), which is not legal C++ syntax
+     for derived types and may be confused with the multiple inheritance
+     form:
+
+     class C : public B : public A {
+     int c;
+     }
+
+     In general, gdb should try to print the types as closely as possible
+     to the form that they appear in the source code.  */
+
+  void type_print_derivation_info (struct ui_file *stream,
+				   struct type *type) const;
+};
 
 #endif /* P_LANG_H */
diff --git a/gdb/p-typeprint.c b/gdb/p-typeprint.c
index c2c182a9ae9..80b3d4a7667 100644
--- a/gdb/p-typeprint.c
+++ b/gdb/p-typeprint.c
@@ -34,21 +34,12 @@
 #include <ctype.h>
 #include "cli/cli-style.h"
 
-static void pascal_type_print_varspec_suffix (struct type *, struct ui_file *,
-					      int, int, int,
-					      const struct type_print_options *);
-
-static void pascal_type_print_derivation_info (struct ui_file *,
-					       struct type *);
-
-\f
-
-/* LEVEL is the depth to indent lines by.  */
+/* See language.h.  */
 
 void
-pascal_print_type (struct type *type, const char *varstring,
-		   struct ui_file *stream, int show, int level,
-		   const struct type_print_options *flags)
+pascal_language::print_type (struct type *type, const char *varstring,
+			     struct ui_file *stream, int show, int level,
+			     const struct type_print_options *flags) const
 {
   enum type_code code;
   int demangled_args;
@@ -61,7 +52,7 @@ pascal_print_type (struct type *type, const char *varstring,
   if ((code == TYPE_CODE_FUNC
        || code == TYPE_CODE_METHOD))
     {
-      pascal_type_print_varspec_prefix (type, stream, show, 0, flags);
+      type_print_varspec_prefix (type, stream, show, 0, flags);
     }
   /* first the name */
   fputs_filtered (varstring, stream);
@@ -76,26 +67,24 @@ pascal_print_type (struct type *type, const char *varstring,
   if (!(code == TYPE_CODE_FUNC
 	|| code == TYPE_CODE_METHOD))
     {
-      pascal_type_print_varspec_prefix (type, stream, show, 0, flags);
+      type_print_varspec_prefix (type, stream, show, 0, flags);
     }
 
-  pascal_type_print_base (type, stream, show, level, flags);
+  type_print_base (type, stream, show, level, flags);
   /* For demangled function names, we have the arglist as part of the name,
      so don't print an additional pair of ()'s.  */
 
   demangled_args = varstring ? strchr (varstring, '(') != NULL : 0;
-  pascal_type_print_varspec_suffix (type, stream, show, 0, demangled_args,
+  type_print_varspec_suffix (type, stream, show, 0, demangled_args,
 				    flags);
 
 }
 
-/* Print a typedef using Pascal syntax.  TYPE is the underlying type.
-   NEW_SYMBOL is the symbol naming the type.  STREAM is the stream on
-   which to print.  */
+/* See language.h.  */
 
 void
-pascal_print_typedef (struct type *type, struct symbol *new_symbol,
-		      struct ui_file *stream)
+pascal_language::print_typedef (struct type *type, struct symbol *new_symbol,
+				struct ui_file *stream) const
 {
   type = check_typedef (type);
   fprintf_filtered (stream, "type ");
@@ -104,32 +93,11 @@ pascal_print_typedef (struct type *type, struct symbol *new_symbol,
   fprintf_filtered (stream, ";");
 }
 
-/* If TYPE is a derived type, then print out derivation information.
-   Print only the actual base classes of this type, not the base classes
-   of the base classes.  I.e. for the derivation hierarchy:
-
-   class A { int a; };
-   class B : public A {int b; };
-   class C : public B {int c; };
-
-   Print the type of class C as:
-
-   class C : public B {
-   int c;
-   }
-
-   Not as the following (like gdb used to), which is not legal C++ syntax for
-   derived types and may be confused with the multiple inheritance form:
-
-   class C : public B : public A {
-   int c;
-   }
-
-   In general, gdb should try to print the types as closely as possible to
-   the form that they appear in the source code.  */
+/* See p-lang.h.  */
 
-static void
-pascal_type_print_derivation_info (struct ui_file *stream, struct type *type)
+void
+pascal_language::type_print_derivation_info (struct ui_file *stream,
+					     struct type *type) const
 {
   const char *name;
   int i;
@@ -149,11 +117,12 @@ pascal_type_print_derivation_info (struct ui_file *stream, struct type *type)
     }
 }
 
-/* Print the Pascal method arguments ARGS to the file STREAM.  */
+/* See p-lang.h.  */
 
 void
-pascal_type_print_method_args (const char *physname, const char *methodname,
-			       struct ui_file *stream)
+pascal_language::type_print_method_args (const char *physname,
+					 const char *methodname,
+					 struct ui_file *stream) const
 {
   int is_constructor = (startswith (physname, "__ct__"));
   int is_destructor = (startswith (physname, "__dt__"));
@@ -195,18 +164,13 @@ pascal_type_print_method_args (const char *physname, const char *methodname,
     }
 }
 
-/* Print any asterisks or open-parentheses needed before the
-   variable name (to describe its type).
-
-   On outermost call, pass 0 for PASSED_A_PTR.
-   On outermost call, SHOW > 0 means should ignore
-   any typename for TYPE and show its details.
-   SHOW is always zero on recursive calls.  */
+/* See p-lang.h.  */
 
 void
-pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
-				  int show, int passed_a_ptr,
-				  const struct type_print_options *flags)
+pascal_language::type_print_varspec_prefix (struct type *type,
+					    struct ui_file *stream,
+					    int show, int passed_a_ptr,
+					    const struct type_print_options *flags) const
 {
   if (type == 0)
     return;
@@ -220,7 +184,7 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
     {
     case TYPE_CODE_PTR:
       fprintf_filtered (stream, "^");
-      pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1,
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1,
 					flags);
       break;			/* Pointer should be handled normally
 				   in pascal.  */
@@ -241,15 +205,15 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
       if (passed_a_ptr)
 	{
 	  fprintf_filtered (stream, " ");
-	  pascal_type_print_base (TYPE_SELF_TYPE (type),
+	  type_print_base (TYPE_SELF_TYPE (type),
 				  stream, 0, passed_a_ptr, flags);
 	  fprintf_filtered (stream, "::");
 	}
       break;
 
     case TYPE_CODE_REF:
-      pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1,
-					flags);
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1,
+				 flags);
       fprintf_filtered (stream, "&");
       break;
 
@@ -301,14 +265,16 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
 	 gcc -Wall will reveal any types that haven't been handled.  */
       break;
     default:
-      error (_("type not handled in pascal_type_print_varspec_prefix()"));
+      gdb_assert_not_reached ("unexpected type");
       break;
     }
 }
 
-static void
-pascal_print_func_args (struct type *type, struct ui_file *stream,
-			const struct type_print_options *flags)
+/* See p-lang.h.  */
+
+void
+pascal_language::print_func_args (struct type *type, struct ui_file *stream,
+				  const struct type_print_options *flags) const
 {
   int i, len = type->num_fields ();
 
@@ -324,12 +290,12 @@ pascal_print_func_args (struct type *type, struct ui_file *stream,
 	  wrap_here ("    ");
 	}
       /*  Can we find if it is a var parameter ??
-	 if ( TYPE_FIELD(type, i) == )
-	 {
-	 fprintf_filtered (stream, "var ");
-	 } */
-      pascal_print_type (type->field (i).type (), ""	/* TYPE_FIELD_NAME
-							   seems invalid!  */
+	  if ( TYPE_FIELD(type, i) == )
+	  {
+	    fprintf_filtered (stream, "var ");
+	  } */
+      print_type (type->field (i).type (), ""	/* TYPE_FIELD_NAME
+						   seems invalid!  */
 			 ,stream, -1, 0, flags);
     }
   if (len)
@@ -338,42 +304,41 @@ pascal_print_func_args (struct type *type, struct ui_file *stream,
     }
 }
 
-/* Helper for pascal_type_print_varspec_suffix to print the suffix of
-   a function or method.  */
+/* See p-lang.h.  */
 
-static void
-pascal_type_print_func_varspec_suffix  (struct type *type, struct ui_file *stream,
-					int show, int passed_a_ptr,
-					int demangled_args,
-					const struct type_print_options *flags)
+void
+pascal_language::type_print_func_varspec_suffix  (struct type *type,
+						  struct ui_file *stream,
+						  int show, int passed_a_ptr,
+						  int demangled_args,
+						  const struct type_print_options *flags) const
 {
   if (TYPE_TARGET_TYPE (type) == NULL
       || TYPE_TARGET_TYPE (type)->code () != TYPE_CODE_VOID)
     {
       fprintf_filtered (stream, " : ");
-      pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
 					stream, 0, 0, flags);
 
       if (TYPE_TARGET_TYPE (type) == NULL)
 	type_print_unknown_return_type (stream);
       else
-	pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0,
+	type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0,
 				flags);
 
-      pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
-					passed_a_ptr, 0, flags);
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+				 passed_a_ptr, 0, flags);
     }
 }
 
-/* Print any array sizes, function arguments or close parentheses
-   needed after the variable name (to describe its type).
-   Args work like pascal_type_print_varspec_prefix.  */
+/* See p-lang.h.  */
 
-static void
-pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
-				  int show, int passed_a_ptr,
-				  int demangled_args,
-				  const struct type_print_options *flags)
+void
+pascal_language::type_print_varspec_suffix (struct type *type,
+					    struct ui_file *stream,
+					    int show, int passed_a_ptr,
+					    int demangled_args,
+					    const struct type_print_options *flags) const
 {
   if (type == 0)
     return;
@@ -393,25 +358,23 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
     case TYPE_CODE_METHOD:
       if (passed_a_ptr)
 	fprintf_filtered (stream, ")");
-      pascal_type_print_method_args ("",
-				     "",
-				     stream);
-      pascal_type_print_func_varspec_suffix (type, stream, show,
+      type_print_method_args ("", "", stream);
+      type_print_func_varspec_suffix (type, stream, show,
 					     passed_a_ptr, 0, flags);
       break;
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
-      pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type),
-					stream, 0, 1, 0, flags);
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type),
+				 stream, 0, 1, 0, flags);
       break;
 
     case TYPE_CODE_FUNC:
       if (passed_a_ptr)
 	fprintf_filtered (stream, ")");
       if (!demangled_args)
-	pascal_print_func_args (type, stream, flags);
-      pascal_type_print_func_varspec_suffix (type, stream, show,
+	print_func_args (type, stream, flags);
+      type_print_func_varspec_suffix (type, stream, show,
 					     passed_a_ptr, 0, flags);
       break;
 
@@ -435,30 +398,16 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
 	 gcc -Wall will report types that may not have been considered.  */
       break;
     default:
-      error (_("type not handled in pascal_type_print_varspec_suffix()"));
+      gdb_assert_not_reached ("unexpected type");
       break;
     }
 }
 
-/* Print the name of the type (or the ultimate pointer target,
-   function value or array element), or the description of a
-   structure or union.
-
-   SHOW positive means print details about the type (e.g. enum values),
-   and print structure elements passing SHOW - 1 for show.
-   SHOW negative means just print the type name or struct tag if there is one.
-   If there is no name, print something sensible but concise like
-   "struct {...}".
-   SHOW zero means just print the type name or struct tag if there is one.
-   If there is no name, print something sensible but not as concise like
-   "struct {int x; int y;}".
-
-   LEVEL is the number of spaces to indent by.
-   We increase it for some recursive calls.  */
+/* See p-lang.h.  */
 
 void
-pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
-			int level, const struct type_print_options *flags)
+pascal_language::type_print_base (struct type *type, struct ui_file *stream, int show,
+				  int level, const struct type_print_options *flags) const
 {
   int i;
   int len;
@@ -502,27 +451,16 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
     case TYPE_CODE_TYPEDEF:
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
-      /* case TYPE_CODE_FUNC:
-	 case TYPE_CODE_METHOD: */
-      pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level,
-			      flags);
+      type_print_base (TYPE_TARGET_TYPE (type), stream, show, level,
+		       flags);
       break;
 
     case TYPE_CODE_ARRAY:
-      /* pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-					   stream, 0, 0);
-	 pascal_type_print_base (TYPE_TARGET_TYPE (type),
-				 stream, show, level);
-	 pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type),
-					   stream, 0, 0, 0); */
-      pascal_print_type (TYPE_TARGET_TYPE (type), NULL, stream, 0, 0, flags);
+      print_type (TYPE_TARGET_TYPE (type), NULL, stream, 0, 0, flags);
       break;
 
     case TYPE_CODE_FUNC:
     case TYPE_CODE_METHOD:
-      /*
-	 pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
-	 only after args !!  */
       break;
     case TYPE_CODE_STRUCT:
       if (type->name () != NULL)
@@ -558,7 +496,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
 	}
       else if (show > 0 || type->name () == NULL)
 	{
-	  pascal_type_print_derivation_info (stream, type);
+	  type_print_derivation_info (stream, type);
 
 	  fprintf_filtered (stream, "\n");
 	  if ((type->num_fields () == 0) && (TYPE_NFN_FIELDS (type) == 0))
@@ -622,7 +560,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
 	      print_spaces_filtered (level + 4, stream);
 	      if (field_is_static (&type->field (i)))
 		fprintf_filtered (stream, "static ");
-	      pascal_print_type (type->field (i).type (),
+	      print_type (type->field (i).type (),
 				 TYPE_FIELD_NAME (type, i),
 				 stream, show - 1, level + 4, flags);
 	      if (!field_is_static (&type->field (i))
@@ -719,9 +657,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
 		    }
 		  /* This does not work, no idea why !!  */
 
-		  pascal_type_print_method_args (physname,
-						 method_name,
-						 stream);
+		  type_print_method_args (physname, method_name, stream);
 
 		  if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) != 0
 		      && TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE(f, j))->code () != TYPE_CODE_VOID)
@@ -807,7 +743,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
 
     case TYPE_CODE_SET:
       fputs_filtered ("set of ", stream);
-      pascal_print_type (type->index_type (), "", stream,
+      print_type (type->index_type (), "", stream,
 			 show - 1, level, flags);
       break;
 
diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c
index 428b2efc656..d2eb9c11750 100644
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -64,9 +64,9 @@ static const struct generic_val_print_decorations p_decorations =
 /* See p-lang.h.  */
 
 void
-pascal_value_print_inner (struct value *val, struct ui_file *stream,
-			  int recurse,
-			  const struct value_print_options *options)
+pascal_language::value_print_inner (struct value *val,
+				    struct ui_file *stream, int recurse,
+				    const struct value_print_options *options) const
 
 {
   struct type *type = check_typedef (value_type (val));
@@ -200,8 +200,8 @@ pascal_value_print_inner (struct value *val, struct ui_file *stream,
 	 as GDB does not recognize stabs pascal strings
 	 Pascal strings are mapped to records
 	 with lowercase names PM.  */
-      if (is_pascal_string_type (elttype, &length_pos, &length_size,
-				 &string_pos, &char_type, NULL)
+      if (pascal_is_string_type (elttype, &length_pos, &length_size,
+				 &string_pos, &char_type, NULL) > 0
 	  && addr != 0)
 	{
 	  ULONGEST string_length;
@@ -313,8 +313,8 @@ pascal_value_print_inner (struct value *val, struct ui_file *stream,
 	}
       else
 	{
-	  if (is_pascal_string_type (type, &length_pos, &length_size,
-				     &string_pos, &char_type, NULL))
+          if (pascal_is_string_type (type, &length_pos, &length_size,
+				     &string_pos, &char_type, NULL) > 0)
 	    {
 	      len = extract_unsigned_integer (valaddr + length_pos,
 					      length_size, byte_order);
@@ -401,8 +401,8 @@ pascal_value_print_inner (struct value *val, struct ui_file *stream,
 
 \f
 void
-pascal_value_print (struct value *val, struct ui_file *stream,
-		    const struct value_print_options *options)
+pascal_language::value_print (struct value *val, struct ui_file *stream,
+			      const struct value_print_options *options) const
 {
   struct type *type = value_type (val);
   struct value_print_options opts = *options;
@@ -498,9 +498,7 @@ pascal_object_is_vtbl_member (struct type *type)
   return 0;
 }
 
-/* Mutually recursive subroutines of pascal_object_print_value and
-   pascal_value_print to print out a structure's fields:
-   pascal_object_print_value_fields and pascal_object_print_value.
+/* Helper function for print pascal objects.
 
    VAL, STREAM, RECURSE, and OPTIONS have the same meanings as in
    pascal_object_print_value and c_value_print.
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 7/9] gdb/objc: fix bug in objc_language::opcode_print_table
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (5 preceding siblings ...)
  2020-11-20 11:55 ` [PATCH 6/9] gdb: move pascal_language into p-lang.h Andrew Burgess
@ 2020-11-20 11:55 ` Andrew Burgess
  2020-11-20 11:55 ` [PATCH 8/9] gdb: move rust_language into rust-lang.h Andrew Burgess
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:55 UTC (permalink / raw)
  To: gdb-patches

In this commit:

  commit b7c6e27dbbbbe678b2e2f0bf617605e055e1b378
  Date:   Tue Aug 4 17:07:59 2020 +0100

      gdb: Convert language_data::la_op_print_tab to a method

A bug was introduced, the objc language now returns the wrong op_print
table.  Fixed in this commit.

gdb/ChangeLog:

	* objc-lang.c (objc_language::opcode_print_table): Return
	objc_op_print_tab.
---
 gdb/ChangeLog   | 5 +++++
 gdb/objc-lang.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 4cd853249aa..4e58c62e4fd 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -424,7 +424,7 @@ class objc_language : public language_defn
   /* See language.h.  */
 
   const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
+  { return objc_op_print_tab; }
 };
 
 /* Single instance of the class representing the Objective-C language.  */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 8/9] gdb: move rust_language into rust-lang.h
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (6 preceding siblings ...)
  2020-11-20 11:55 ` [PATCH 7/9] gdb/objc: fix bug in objc_language::opcode_print_table Andrew Burgess
@ 2020-11-20 11:55 ` Andrew Burgess
  2020-11-20 11:55 ` [PATCH 9/9] gdb: remove some uses of LA_PRINT_STRING Andrew Burgess
  2020-12-10 16:26 ` [PATCH 0/9] Further language class related changes Andrew Burgess
  9 siblings, 0 replies; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:55 UTC (permalink / raw)
  To: gdb-patches

Move the rust_language class declaration into the rust-lang.h header
file.  This allows for the function implementations called directly in
rust-lang.c and rust-exp.y without the need for trampoline functions.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* rust-exp.y (rust_parse): Rename to...
	(rust_language::parser): ...this.
	* rust-lang.c (-rust_printstr): Rename to...
	(rust_language::printstr): ...this.
	(rust_value_print_inner): Delete declaration.
	(val_print_struct): Rename to...
	(rust_language::val_print_struct): ...this.  Update calls to
	member functions.
	(rust_print_enum): Rename to...
	(rust_language::print_enum): ...this.  Update calls to member
	functions.
	(rust_value_print_inner): Rename to...
	(rust_language::value_print_inner): ...this.  Update calls to
	member functions.
	(exp_descriptor_rust): Rename to...
	(rust_language::exp_descriptor_tab): ...this.
	(class rust_language): Move to rust-lang.h.
	(rust_language::language_arch_info): Implementation moved to here
	from class declaration.
	(rust_language::print_type): Likewise.
	(rust_language::emitchar): Likewise.
	(rust_language::is_string_type_p): Likewise.
	* rust-lang.h: Add 'demangle.h', 'language.h', 'value.h', and
	'c-lang.h' includes.
	(rust_parse): Delete declaration.
	(class rust_language): Class declaration moved here from
	rust-lang.c.
---
 gdb/ChangeLog   |  30 ++++
 gdb/rust-exp.y  |   2 +-
 gdb/rust-lang.c | 397 +++++++++++++++---------------------------------
 gdb/rust-lang.h | 198 +++++++++++++++++++++++-
 4 files changed, 346 insertions(+), 281 deletions(-)

diff --git a/gdb/rust-exp.y b/gdb/rust-exp.y
index 1207d1d6f42..02885006df3 100644
--- a/gdb/rust-exp.y
+++ b/gdb/rust-exp.y
@@ -2540,7 +2540,7 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 /* The parser as exposed to gdb.  */
 
 int
-rust_parse (struct parser_state *state)
+rust_language::parser (struct parser_state *state) const
 {
   int result;
 
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 4cfe44a1ad7..10858431490 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -261,13 +261,13 @@ rust_get_trait_object_pointer (struct value *value)
 
 \f
 
-/* language_defn::printstr implementation for Rust.  */
+/* See language.h.  */
 
-static void
-rust_printstr (struct ui_file *stream, struct type *type,
-	       const gdb_byte *string, unsigned int length,
-	       const char *user_encoding, int force_ellipses,
-	       const struct value_print_options *options)
+void
+rust_language::printstr (struct ui_file *stream, struct type *type,
+			 const gdb_byte *string, unsigned int length,
+			 const char *user_encoding, int force_ellipses,
+			 const struct value_print_options *options) const
 {
   /* Rust always uses UTF-8, but let the caller override this if need
      be.  */
@@ -294,10 +294,6 @@ rust_printstr (struct ui_file *stream, struct type *type,
 
 \f
 
-static void rust_value_print_inner (struct value *val, struct ui_file *stream,
-				    int recurse,
-				    const struct value_print_options *options);
-
 /* Helper function to print a string slice.  */
 
 static void
@@ -313,11 +309,12 @@ rust_val_print_str (struct ui_file *stream, struct value *val,
 		    options);
 }
 
-/* rust_val_print helper for structs and untagged unions.  */
+/* See rust-lang.h.  */
 
-static void
-val_print_struct (struct value *val, struct ui_file *stream, int recurse,
-		  const struct value_print_options *options)
+void
+rust_language::val_print_struct
+	(struct value *val, struct ui_file *stream, int recurse,
+	 const struct value_print_options *options) const
 {
   int i;
   int first_field;
@@ -387,8 +384,7 @@ val_print_struct (struct value *val, struct ui_file *stream, int recurse,
 	  fputs_filtered (": ", stream);
 	}
 
-      rust_value_print_inner (value_field (val, i), stream, recurse + 1,
-			      &opts);
+      value_print_inner (value_field (val, i), stream, recurse + 1, &opts);
     }
 
   if (options->prettyformat)
@@ -403,11 +399,12 @@ val_print_struct (struct value *val, struct ui_file *stream, int recurse,
     fputs_filtered ("}", stream);
 }
 
-/* rust_val_print helper for discriminated unions (Rust enums).  */
+/* See rust-lang.h.  */
 
-static void
-rust_print_enum (struct value *val, struct ui_file *stream, int recurse,
-		 const struct value_print_options *options)
+void
+rust_language::print_enum (struct value *val, struct ui_file *stream,
+			   int recurse,
+			   const struct value_print_options *options) const
 {
   struct value_print_options opts = *options;
   struct type *type = check_typedef (value_type (val));
@@ -465,8 +462,7 @@ rust_print_enum (struct value *val, struct ui_file *stream, int recurse,
 			  styled_string (variable_name_style.style (),
 					 TYPE_FIELD_NAME (variant_type, j)));
 
-      rust_value_print_inner (value_field (val, j), stream, recurse + 1,
-			      &opts);
+      value_print_inner (value_field (val, j), stream, recurse + 1, &opts);
     }
 
   if (is_tuple)
@@ -489,11 +485,12 @@ static const struct generic_val_print_decorations rust_decorations =
   "]"
 };
 
-/* la_value_print_inner implementation for Rust.  */
-static void
-rust_value_print_inner (struct value *val, struct ui_file *stream,
-			int recurse,
-			const struct value_print_options *options)
+/* See language.h.  */
+
+void
+rust_language::value_print_inner
+	(struct value *val, struct ui_file *stream, int recurse,
+	 const struct value_print_options *options) const
 {
   struct value_print_options opts = *options;
   opts.deref_ref = 1;
@@ -556,9 +553,9 @@ rust_value_print_inner (struct value *val, struct ui_file *stream,
 	   byte string, hence the choice of "ASCII" as the
 	   encoding.  */
 	fputs_filtered ("b", stream);
-	rust_printstr (stream, TYPE_TARGET_TYPE (type),
-		       value_contents_for_printing (val),
-		       high_bound - low_bound + 1, "ASCII", 0, &opts);
+	printstr (stream, TYPE_TARGET_TYPE (type),
+		  value_contents_for_printing (val),
+		  high_bound - low_bound + 1, "ASCII", 0, &opts);
       }
       break;
 
@@ -585,7 +582,7 @@ rust_value_print_inner (struct value *val, struct ui_file *stream,
 
     case TYPE_CODE_STRUCT:
       if (rust_enum_p (type))
-	rust_print_enum (val, stream, recurse, &opts);
+	print_enum (val, stream, recurse, &opts);
       else
 	val_print_struct (val, stream, recurse, &opts);
       break;
@@ -1863,7 +1860,7 @@ rust_operator_check (struct expression *exp, int pos,
 
 \f
 
-static const struct exp_descriptor exp_descriptor_rust = 
+const struct exp_descriptor rust_language::exp_descriptor_tab =
 {
   rust_print_subexp,
   rust_operator_length,
@@ -1873,262 +1870,108 @@ static const struct exp_descriptor exp_descriptor_rust =
   rust_evaluate_subexp
 };
 
-/* Class representing the Rust language.  */
+/* See language.h.  */
 
-class rust_language : public language_defn
+void
+rust_language::language_arch_info (struct gdbarch *gdbarch,
+				   struct language_arch_info *lai) const
 {
-public:
-  rust_language ()
-    : language_defn (language_rust)
-  { /* Nothing.  */ }
-
-  /* See language.h.  */
-
-  const char *name () const override
-  { return "rust"; }
-
-  /* See language.h.  */
-
-  const char *natural_name () const override
-  { return "Rust"; }
-
-  /* See language.h.  */
-
-  const std::vector<const char *> &filename_extensions () const override
-  {
-    static const std::vector<const char *> extensions = { ".rs" };
-    return extensions;
-  }
-
-  /* See language.h.  */
-  void language_arch_info (struct gdbarch *gdbarch,
-			   struct language_arch_info *lai) const override
-  {
-    const struct builtin_type *builtin = builtin_type (gdbarch);
-
-    /* Helper function to allow shorter lines below.  */
-    auto add  = [&] (struct type * t) -> struct type *
-    {
-      lai->add_primitive_type (t);
-      return t;
-    };
-
-    struct type *bool_type
-      = add (arch_boolean_type (gdbarch, 8, 1, "bool"));
-    add (arch_character_type (gdbarch, 32, 1, "char"));
-    add (arch_integer_type (gdbarch, 8, 0, "i8"));
-    struct type *u8_type
-      = add (arch_integer_type (gdbarch, 8, 1, "u8"));
-    add (arch_integer_type (gdbarch, 16, 0, "i16"));
-    add (arch_integer_type (gdbarch, 16, 1, "u16"));
-    add (arch_integer_type (gdbarch, 32, 0, "i32"));
-    add (arch_integer_type (gdbarch, 32, 1, "u32"));
-    add (arch_integer_type (gdbarch, 64, 0, "i64"));
-    add (arch_integer_type (gdbarch, 64, 1, "u64"));
-
-    unsigned int length = 8 * TYPE_LENGTH (builtin->builtin_data_ptr);
-    add (arch_integer_type (gdbarch, length, 0, "isize"));
-    struct type *usize_type
-      = add (arch_integer_type (gdbarch, length, 1, "usize"));
-
-    add (arch_float_type (gdbarch, 32, "f32", floatformats_ieee_single));
-    add (arch_float_type (gdbarch, 64, "f64", floatformats_ieee_double));
-    add (arch_integer_type (gdbarch, 0, 1, "()"));
-
-    struct type *tem = make_cv_type (1, 0, u8_type, NULL);
-    add (rust_slice_type ("&str", tem, usize_type));
-
-    lai->set_bool_type (bool_type);
-    lai->set_string_char_type (u8_type);
-  }
-
-  /* See language.h.  */
-  bool sniff_from_mangled_name (const char *mangled,
-				char **demangled) const override
-  {
-    *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
-    return *demangled != NULL;
-  }
-
-  /* See language.h.  */
-
-  char *demangle_symbol (const char *mangled, int options) const override
-  {
-    return gdb_demangle (mangled, options);
-  }
-
-  /* See language.h.  */
-
-  void print_type (struct type *type, const char *varstring,
-		   struct ui_file *stream, int show, int level,
-		   const struct type_print_options *flags) const override
-  {
-    print_offset_data podata;
-    rust_internal_print_type (type, varstring, stream, show, level,
-			      flags, false, &podata);
-  }
-
-  /* See language.h.  */
-
-  gdb::unique_xmalloc_ptr<char> watch_location_expression
-	(struct type *type, CORE_ADDR addr) const override
-  {
-    type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
-    std::string name = type_to_string (type);
-    return gdb::unique_xmalloc_ptr<char>
-      (xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr),
-		   name.c_str ()));
-  }
-
-  /* See language.h.  */
-
-  void value_print_inner
-	(struct value *val, struct ui_file *stream, int recurse,
-	 const struct value_print_options *options) const override
-  {
-    return rust_value_print_inner (val, stream, recurse, options);
-  }
-
-  /* See language.h.  */
-
-  struct block_symbol lookup_symbol_nonlocal
-	(const char *name, const struct block *block,
-	 const domain_enum domain) const override
-  {
-    struct block_symbol result = {};
-
-    if (symbol_lookup_debug)
-      {
-	fprintf_unfiltered (gdb_stdlog,
-			    "rust_lookup_symbol_non_local"
-			    " (%s, %s (scope %s), %s)\n",
-			    name, host_address_to_string (block),
-			    block_scope (block), domain_name (domain));
-      }
-
-    /* Look up bare names in the block's scope.  */
-    std::string scopedname;
-    if (name[cp_find_first_component (name)] == '\0')
-      {
-	const char *scope = block_scope (block);
-
-	if (scope[0] != '\0')
-	  {
-	    scopedname = std::string (scope) + "::" + name;
-	    name = scopedname.c_str ();
-	  }
-	else
-	  name = NULL;
-      }
-
-    if (name != NULL)
-      {
-	result = lookup_symbol_in_static_block (name, block, domain);
-	if (result.symbol == NULL)
-	  result = lookup_global_symbol (name, block, domain);
-      }
-    return result;
-  }
-
-  /* See language.h.  */
+  const struct builtin_type *builtin = builtin_type (gdbarch);
 
-  int parser (struct parser_state *ps) const override
+  /* Helper function to allow shorter lines below.  */
+  auto add  = [&] (struct type * t) -> struct type *
   {
-    return rust_parse (ps);
-  }
-
-  /* See language.h.  */
-
-  void emitchar (int ch, struct type *chtype,
-		 struct ui_file *stream, int quoter) const override
-  {
-    if (!rust_chartype_p (chtype))
-      generic_emit_char (ch, chtype, stream, quoter,
-			 target_charset (get_type_arch (chtype)));
-    else if (ch == '\\' || ch == quoter)
-      fprintf_filtered (stream, "\\%c", ch);
-    else if (ch == '\n')
-      fputs_filtered ("\\n", stream);
-    else if (ch == '\r')
-      fputs_filtered ("\\r", stream);
-    else if (ch == '\t')
-      fputs_filtered ("\\t", stream);
-    else if (ch == '\0')
-      fputs_filtered ("\\0", stream);
-    else if (ch >= 32 && ch <= 127 && isprint (ch))
-      fputc_filtered (ch, stream);
-    else if (ch <= 255)
-      fprintf_filtered (stream, "\\x%02x", ch);
-    else
-      fprintf_filtered (stream, "\\u{%06x}", ch);
-  }
-
-  /* See language.h.  */
-
-  void printchar (int ch, struct type *chtype,
-		  struct ui_file *stream) const override
-  {
-    fputs_filtered ("'", stream);
-    emitchar (ch, chtype, stream, '\'');
-    fputs_filtered ("'", stream);
-  }
-
-  /* See language.h.  */
-
-  void printstr (struct ui_file *stream, struct type *elttype,
-		 const gdb_byte *string, unsigned int length,
-		 const char *encoding, int force_ellipses,
-		 const struct value_print_options *options) const override
-  {
-    rust_printstr (stream, elttype, string, length, encoding,
-		   force_ellipses, options);
-  }
-
-  /* See language.h.  */
-
-  void print_typedef (struct type *type, struct symbol *new_symbol,
-		      struct ui_file *stream) const override
-  {
-    type = check_typedef (type);
-    fprintf_filtered (stream, "type %s = ", new_symbol->print_name ());
-    type_print (type, "", stream, 0);
-    fprintf_filtered (stream, ";");
-  }
-
-  /* See language.h.  */
-
-  bool is_string_type_p (struct type *type) const override
-  {
-    LONGEST low_bound, high_bound;
+    lai->add_primitive_type (t);
+    return t;
+  };
+
+  struct type *bool_type
+    = add (arch_boolean_type (gdbarch, 8, 1, "bool"));
+  add (arch_character_type (gdbarch, 32, 1, "char"));
+  add (arch_integer_type (gdbarch, 8, 0, "i8"));
+  struct type *u8_type
+    = add (arch_integer_type (gdbarch, 8, 1, "u8"));
+  add (arch_integer_type (gdbarch, 16, 0, "i16"));
+  add (arch_integer_type (gdbarch, 16, 1, "u16"));
+  add (arch_integer_type (gdbarch, 32, 0, "i32"));
+  add (arch_integer_type (gdbarch, 32, 1, "u32"));
+  add (arch_integer_type (gdbarch, 64, 0, "i64"));
+  add (arch_integer_type (gdbarch, 64, 1, "u64"));
+
+  unsigned int length = 8 * TYPE_LENGTH (builtin->builtin_data_ptr);
+  add (arch_integer_type (gdbarch, length, 0, "isize"));
+  struct type *usize_type
+    = add (arch_integer_type (gdbarch, length, 1, "usize"));
+
+  add (arch_float_type (gdbarch, 32, "f32", floatformats_ieee_single));
+  add (arch_float_type (gdbarch, 64, "f64", floatformats_ieee_double));
+  add (arch_integer_type (gdbarch, 0, 1, "()"));
+
+  struct type *tem = make_cv_type (1, 0, u8_type, NULL);
+  add (rust_slice_type ("&str", tem, usize_type));
+
+  lai->set_bool_type (bool_type);
+  lai->set_string_char_type (u8_type);
+}
 
-    type = check_typedef (type);
-    return ((type->code () == TYPE_CODE_STRING)
-	    || (type->code () == TYPE_CODE_PTR
-		&& (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ARRAY
-		    && rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
-		    && get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
-					 &high_bound)))
-	    || (type->code () == TYPE_CODE_STRUCT
-		&& !rust_enum_p (type)
-		&& rust_slice_type_p (type)
-		&& strcmp (type->name (), "&str") == 0));
-  }
+/* See language.h.  */
 
-  /* See language.h.  */
+void
+rust_language::print_type (struct type *type, const char *varstring,
+			   struct ui_file *stream, int show, int level,
+			   const struct type_print_options *flags) const
+{
+  print_offset_data podata;
+  rust_internal_print_type (type, varstring, stream, show, level,
+			    flags, false, &podata);
+}
 
-  bool range_checking_on_by_default () const override
-  { return true; }
+/* See language.h.  */
 
-  /* See language.h.  */
+void
+rust_language::emitchar (int ch, struct type *chtype,
+			 struct ui_file *stream, int quoter) const
+{
+  if (!rust_chartype_p (chtype))
+    generic_emit_char (ch, chtype, stream, quoter,
+		       target_charset (get_type_arch (chtype)));
+  else if (ch == '\\' || ch == quoter)
+    fprintf_filtered (stream, "\\%c", ch);
+  else if (ch == '\n')
+    fputs_filtered ("\\n", stream);
+  else if (ch == '\r')
+    fputs_filtered ("\\r", stream);
+  else if (ch == '\t')
+    fputs_filtered ("\\t", stream);
+  else if (ch == '\0')
+    fputs_filtered ("\\0", stream);
+  else if (ch >= 32 && ch <= 127 && isprint (ch))
+    fputc_filtered (ch, stream);
+  else if (ch <= 255)
+    fprintf_filtered (stream, "\\x%02x", ch);
+  else
+    fprintf_filtered (stream, "\\u{%06x}", ch);
+}
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_rust; }
+/* See language.h.  */
 
-  /* See language.h.  */
+bool
+rust_language::is_string_type_p (struct type *type) const
+{
+  LONGEST low_bound, high_bound;
 
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
-};
+  type = check_typedef (type);
+  return ((type->code () == TYPE_CODE_STRING)
+	  || (type->code () == TYPE_CODE_PTR
+	      && (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ARRAY
+		  && rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
+		  && get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
+				       &high_bound)))
+	  || (type->code () == TYPE_CODE_STRUCT
+	      && !rust_enum_p (type)
+	      && rust_slice_type_p (type)
+	      && strcmp (type->name (), "&str") == 0));
+}
 
 /* Single instance of the Rust language class.  */
 
diff --git a/gdb/rust-lang.h b/gdb/rust-lang.h
index 3ab860e086a..df94fc14563 100644
--- a/gdb/rust-lang.h
+++ b/gdb/rust-lang.h
@@ -20,12 +20,14 @@
 #ifndef RUST_LANG_H
 #define RUST_LANG_H
 
+#include "demangle.h"
+#include "language.h"
+#include "value.h"
+#include "c-lang.h"
+
 struct parser_state;
 struct type;
 
-/* The la_parser implementation for Rust.  */
-extern int rust_parse (struct parser_state *);
-
 /* Return true if TYPE is a tuple type; otherwise false.  */
 extern bool rust_tuple_type_p (struct type *type);
 
@@ -48,4 +50,194 @@ extern const char *rust_last_path_segment (const char *path);
 extern struct type *rust_slice_type (const char *name, struct type *elt_type,
 				     struct type *usize_type);
 
+/* Class representing the Rust language.  */
+
+class rust_language : public language_defn
+{
+public:
+  rust_language ()
+    : language_defn (language_rust)
+  { /* Nothing.  */ }
+
+  /* See language.h.  */
+
+  const char *name () const override
+  { return "rust"; }
+
+  /* See language.h.  */
+
+  const char *natural_name () const override
+  { return "Rust"; }
+
+  /* See language.h.  */
+
+  const std::vector<const char *> &filename_extensions () const override
+  {
+    static const std::vector<const char *> extensions = { ".rs" };
+    return extensions;
+  }
+
+  /* See language.h.  */
+
+  void language_arch_info (struct gdbarch *gdbarch,
+			   struct language_arch_info *lai) const override;
+
+  /* See language.h.  */
+
+  bool sniff_from_mangled_name (const char *mangled,
+				char **demangled) const override
+  {
+    *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+    return *demangled != NULL;
+  }
+
+  /* See language.h.  */
+
+  char *demangle_symbol (const char *mangled, int options) const override
+  {
+    return gdb_demangle (mangled, options);
+  }
+
+  /* See language.h.  */
+
+  void print_type (struct type *type, const char *varstring,
+		   struct ui_file *stream, int show, int level,
+		   const struct type_print_options *flags) const override;
+
+  /* See language.h.  */
+
+  gdb::unique_xmalloc_ptr<char> watch_location_expression
+	(struct type *type, CORE_ADDR addr) const override
+  {
+    type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
+    std::string name = type_to_string (type);
+    return gdb::unique_xmalloc_ptr<char>
+      (xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr),
+		   name.c_str ()));
+  }
+
+  /* See language.h.  */
+
+  void value_print_inner
+	(struct value *val, struct ui_file *stream, int recurse,
+	 const struct value_print_options *options) const override;
+
+  /* See language.h.  */
+
+  struct block_symbol lookup_symbol_nonlocal
+	(const char *name, const struct block *block,
+	 const domain_enum domain) const override
+  {
+    struct block_symbol result = {};
+
+    if (symbol_lookup_debug)
+      {
+	fprintf_unfiltered (gdb_stdlog,
+			    "rust_lookup_symbol_non_local"
+			    " (%s, %s (scope %s), %s)\n",
+			    name, host_address_to_string (block),
+			    block_scope (block), domain_name (domain));
+      }
+
+    /* Look up bare names in the block's scope.  */
+    std::string scopedname;
+    if (name[cp_find_first_component (name)] == '\0')
+      {
+	const char *scope = block_scope (block);
+
+	if (scope[0] != '\0')
+	  {
+	    scopedname = std::string (scope) + "::" + name;
+	    name = scopedname.c_str ();
+	  }
+	else
+	  name = NULL;
+      }
+
+    if (name != NULL)
+      {
+	result = lookup_symbol_in_static_block (name, block, domain);
+	if (result.symbol == NULL)
+	  result = lookup_global_symbol (name, block, domain);
+      }
+    return result;
+  }
+
+  /* See language.h.  */
+
+  int parser (struct parser_state *ps) const override;
+
+  /* See language.h.  */
+
+  void emitchar (int ch, struct type *chtype,
+		 struct ui_file *stream, int quoter) const override;
+
+  /* See language.h.  */
+
+  void printchar (int ch, struct type *chtype,
+		  struct ui_file *stream) const override
+  {
+    fputs_filtered ("'", stream);
+    emitchar (ch, chtype, stream, '\'');
+    fputs_filtered ("'", stream);
+  }
+
+  /* See language.h.  */
+
+  void printstr (struct ui_file *stream, struct type *elttype,
+		 const gdb_byte *string, unsigned int length,
+		 const char *encoding, int force_ellipses,
+		 const struct value_print_options *options) const override;
+
+  /* See language.h.  */
+
+  void print_typedef (struct type *type, struct symbol *new_symbol,
+		      struct ui_file *stream) const override
+  {
+    type = check_typedef (type);
+    fprintf_filtered (stream, "type %s = ", new_symbol->print_name ());
+    type_print (type, "", stream, 0);
+    fprintf_filtered (stream, ";");
+  }
+
+  /* See language.h.  */
+
+  bool is_string_type_p (struct type *type) const override;
+
+  /* See language.h.  */
+
+  bool range_checking_on_by_default () const override
+  { return true; }
+
+  /* See language.h.  */
+
+  const struct exp_descriptor *expression_ops () const override
+  { return &exp_descriptor_tab; }
+
+  /* See language.h.  */
+
+  const struct op_print *opcode_print_table () const override
+  { return c_op_print_tab; }
+
+private:
+
+  /* Table of expression handling functions for use by EXPRESSION_OPS
+     member function.  */
+
+  static const struct exp_descriptor exp_descriptor_tab;
+
+  /* Helper for value_print_inner, arguments are as for that function.
+     Prints structs and untagged unions.  */
+
+  void val_print_struct (struct value *val, struct ui_file *stream,
+			 int recurse,
+			 const struct value_print_options *options) const;
+
+  /* Helper for value_print_inner, arguments are as for that function.
+     Prints discriminated unions (Rust enums).  */
+
+  void print_enum (struct value *val, struct ui_file *stream, int recurse,
+		   const struct value_print_options *options) const;
+};
+
 #endif /* RUST_LANG_H */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 9/9] gdb: remove some uses of LA_PRINT_STRING
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (7 preceding siblings ...)
  2020-11-20 11:55 ` [PATCH 8/9] gdb: move rust_language into rust-lang.h Andrew Burgess
@ 2020-11-20 11:55 ` Andrew Burgess
  2020-12-10 20:51   ` Tom Tromey
  2020-12-10 16:26 ` [PATCH 0/9] Further language class related changes Andrew Burgess
  9 siblings, 1 reply; 14+ messages in thread
From: Andrew Burgess @ 2020-11-20 11:55 UTC (permalink / raw)
  To: gdb-patches

This commit removes some, but not all, uses of LA_PRINT_STRING.  In
this commit I've removed those uses where there is an obvious language
object on which I can instead call the printstr method.

In the remaining 3 uses it is harder to know if the correct thing is
to call printstr on the current language, or on a specific language.
Currently obviously, we always call on the current language (as that's
what LA_PRINT_STRING does), and clearly this behaviour is good enough
right now, but is it "right"?  I've left them for now and will give
them more thought in the future.

gdb/ChangeLog:

	* expprint.c (print_subexp_standard): Replace uses of
	LA_PRINT_STRING.
	* f-valprint.c (f_language::value_print_inner): Likewise.
	* guile/scm-pretty-print.c (ppscm_print_string_repr): Likewise.
	* p-valprint.c (pascal_language::value_print_inner): Likewise.
	* python/py-prettyprint.c (print_string_repr): Likewise.
---
 gdb/ChangeLog                |  9 +++++++++
 gdb/expprint.c               | 19 +++++++++++--------
 gdb/f-valprint.c             | 10 +++++-----
 gdb/guile/scm-pretty-print.c |  4 ++--
 gdb/p-valprint.c             |  8 ++++----
 gdb/python/py-prettyprint.c  |  4 ++--
 6 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/gdb/expprint.c b/gdb/expprint.c
index 29e6237ab4d..950643a3777 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -226,9 +226,10 @@ print_subexp_standard (struct expression *exp, int *pos,
 	   If necessary, we can temporarily set it to zero, or pass it as an
 	   additional parameter to LA_PRINT_STRING.  -fnf */
 	get_user_print_options (&opts);
-	LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char,
-			 (gdb_byte *) &exp->elts[pc + 2].string, nargs,
-			 NULL, 0, &opts);
+	exp->language_defn
+	  ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
+		      (gdb_byte *) &exp->elts[pc + 2].string, nargs,
+		      NULL, 0, &opts);
       }
       return;
 
@@ -241,9 +242,10 @@ print_subexp_standard (struct expression *exp, int *pos,
 	(*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
 	fputs_filtered ("@\"", stream);
 	get_user_print_options (&opts);
-	LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char,
-			 (gdb_byte *) &exp->elts[pc + 2].string, nargs,
-			 NULL, 0, &opts);
+	exp->language_defn
+	  ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
+		      (gdb_byte *) &exp->elts[pc + 2].string, nargs,
+		      NULL, 0, &opts);
 	fputs_filtered ("\"", stream);
       }
       return;
@@ -325,8 +327,9 @@ print_subexp_standard (struct expression *exp, int *pos,
 	  struct value_print_options opts;
 
 	  get_user_print_options (&opts);
-	  LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char,
-			   (gdb_byte *) tempstr, nargs - 1, NULL, 0, &opts);
+	  exp->language_defn
+	    ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
+			(gdb_byte *) tempstr, nargs - 1, NULL, 0, &opts);
 	  (*pos) = pc;
 	}
       else
diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c
index d147caa36fc..63cd9b3bd6b 100644
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -235,8 +235,8 @@ f_language::value_print_inner (struct value *val, struct ui_file *stream,
     {
     case TYPE_CODE_STRING:
       f77_get_dynamic_length_of_aggregate (type);
-      LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char,
-		       valaddr, TYPE_LENGTH (type), NULL, 0, options);
+      printstr (stream, builtin_type (gdbarch)->builtin_char, valaddr,
+		TYPE_LENGTH (type), NULL, 0, options);
       break;
 
     case TYPE_CODE_ARRAY:
@@ -247,9 +247,9 @@ f_language::value_print_inner (struct value *val, struct ui_file *stream,
 	  struct type *ch_type = TYPE_TARGET_TYPE (type);
 
 	  f77_get_dynamic_length_of_aggregate (type);
-	  LA_PRINT_STRING (stream, ch_type, valaddr,
-			   TYPE_LENGTH (type) / TYPE_LENGTH (ch_type),
-			   NULL, 0, options);
+	  printstr (stream, ch_type, valaddr,
+		    TYPE_LENGTH (type) / TYPE_LENGTH (ch_type), NULL, 0,
+		    options);
 	}
       break;
 
diff --git a/gdb/guile/scm-pretty-print.c b/gdb/guile/scm-pretty-print.c
index df09dae434e..061868512d1 100644
--- a/gdb/guile/scm-pretty-print.c
+++ b/gdb/guile/scm-pretty-print.c
@@ -675,8 +675,8 @@ ppscm_print_string_repr (SCM printer, enum display_hint hint,
 	{
 	  struct type *type = builtin_type (gdbarch)->builtin_char;
 	  
-	  LA_PRINT_STRING (stream, type, (gdb_byte *) string.get (),
-			   length, NULL, 0, options);
+	  language->printstr (stream, type, (gdb_byte *) string.get (),
+			      length, NULL, 0, options);
 	}
       else
 	{
diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c
index d2eb9c11750..496a872fd5e 100644
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -116,8 +116,8 @@ pascal_language::value_print_inner (struct value *val,
 		    len = temp_len;
 		  }
 
-		LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type),
-				 valaddr, len, NULL, 0, options);
+		printstr (stream, TYPE_TARGET_TYPE (type), valaddr, len,
+			  NULL, 0, options);
 		i = len;
 	      }
 	    else
@@ -318,8 +318,8 @@ pascal_language::value_print_inner (struct value *val,
 	    {
 	      len = extract_unsigned_integer (valaddr + length_pos,
 					      length_size, byte_order);
-	      LA_PRINT_STRING (stream, char_type, valaddr + string_pos,
-			       len, NULL, 0, options);
+	      printstr (stream, char_type, valaddr + string_pos, len,
+			NULL, 0, options);
 	    }
 	  else
 	    pascal_object_print_value_fields (val, stream, recurse,
diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c
index 8eaa41fb187..6300cb0bc57 100644
--- a/gdb/python/py-prettyprint.c
+++ b/gdb/python/py-prettyprint.c
@@ -318,8 +318,8 @@ print_string_repr (PyObject *printer, const char *hint,
 	      type = builtin_type (gdbarch)->builtin_char;
 
 	      if (hint && !strcmp (hint, "string"))
-		LA_PRINT_STRING (stream, type, (gdb_byte *) output,
-				 length, NULL, 0, options);
+		language->printstr (stream, type, (gdb_byte *) output,
+				    length, NULL, 0, options);
 	      else
 		fputs_filtered (output, stream);
 	    }
-- 
2.25.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/9] Further language class related changes
  2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
                   ` (8 preceding siblings ...)
  2020-11-20 11:55 ` [PATCH 9/9] gdb: remove some uses of LA_PRINT_STRING Andrew Burgess
@ 2020-12-10 16:26 ` Andrew Burgess
  2020-12-10 20:51   ` Tom Tromey
  9 siblings, 1 reply; 14+ messages in thread
From: Andrew Burgess @ 2020-12-10 16:26 UTC (permalink / raw)
  To: gdb-patches

* Andrew Burgess <andrew.burgess@embecosm.com> [2020-11-20 11:54:55 +0000]:

> The changes in this series do two things:
> 
>  1. Reduce the use of the LA_* macros from language.h, with
>     LA_EMIT_CHAR being completely removed, and LA_PRINT_STRING being
>     reduced in usage.
> 
>  2. Move some additional language classes into the language's header
>     file.  This allows functions defined in different *.c files to be
>     renamed as language_class::member_function rather than having to
>     trampoline from the member function to a global.
> 
> The patch that's most worth reviewing is, I think #2 where I replace
> direct calls to a global function with calls to a language classes
> member functions.
> 
> All feedback welcome.

Unless someone shouts out I plan to push this series in the next few
days.

Thanks,
Andrew




> 
> Thanks,
> Andrew
> 
> 
> ---
> 
> Andrew Burgess (9):
>   gdb: delete unused function print_char_chars
>   gdb: avoid accessing global C++ language implementation functions
>   gdb: rename c_printchar as language_defn::printchar
>   gdb: remove LA_EMIT_CHAR macro
>   gdb: move go_language class declaration into header file
>   gdb: move pascal_language into p-lang.h
>   gdb/objc: fix bug in objc_language::opcode_print_table
>   gdb: move rust_language into rust-lang.h
>   gdb: remove some uses of LA_PRINT_STRING
> 
>  gdb/ChangeLog                | 162 ++++++++++++++
>  gdb/c-lang.c                 |   7 +-
>  gdb/c-lang.h                 |   2 -
>  gdb/dwarf2/read.c            |   7 +-
>  gdb/expprint.c               |  19 +-
>  gdb/f-lang.h                 |   2 +-
>  gdb/f-valprint.c             |  10 +-
>  gdb/go-exp.y                 |   4 +-
>  gdb/go-lang.c                | 164 ++++-----------
>  gdb/go-lang.h                |  94 +++++++--
>  gdb/go-typeprint.c           |   6 +-
>  gdb/go-valprint.c            |   5 +-
>  gdb/guile/scm-pretty-print.c |   4 +-
>  gdb/language.c               |   9 -
>  gdb/language.h               |   2 -
>  gdb/objc-lang.c              |   2 +-
>  gdb/p-exp.y                  |  11 +-
>  gdb/p-lang.c                 | 384 ++++++++++++---------------------
>  gdb/p-lang.h                 | 245 ++++++++++++++++++---
>  gdb/p-typeprint.c            | 214 +++++++------------
>  gdb/p-valprint.c             |  30 ++-
>  gdb/python/py-prettyprint.c  |   4 +-
>  gdb/rust-exp.y               |   2 +-
>  gdb/rust-lang.c              | 397 +++++++++++------------------------
>  gdb/rust-lang.h              | 198 ++++++++++++++++-
>  gdb/symtab.c                 |   3 +-
>  gdb/valprint.c               |  37 ----
>  gdb/valprint.h               |   3 -
>  28 files changed, 1089 insertions(+), 938 deletions(-)
> 
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/9] gdb: avoid accessing global C++ language implementation functions
  2020-11-20 11:54 ` [PATCH 2/9] gdb: avoid accessing global C++ language implementation functions Andrew Burgess
@ 2020-12-10 20:47   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2020-12-10 20:47 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> The function c_printchar is called from two places; it provides the
Andrew> implementation of language_defn::printchar and it is called from
Andrew> dwarf2_compute_name.

Andrew> It would be nice to rename c_printchar as language_defn::printchar and
Andrew> so avoid the trampoline.

Andrew> To achieve this, instead of calling c_printchar directly from the
Andrew> DWARF code, I lookup the C++ language object and call the printchar
Andrew> member function.

This seems fine to me.

Andrew>  		  if (child->tag == DW_TAG_template_type_param)
Andrew>  		    {
Andrew> -		      c_print_type (type, "", &buf, -1, 0, cu->language,
Andrew> -				    &type_print_raw_options);
Andrew> +		      cplus_lang->print_type (type, "", &buf, -1, 0,
Andrew> +					      &type_print_raw_options);
Andrew>  		      continue;
Andrew>  		    }

I wish we could just remove this code.  Calling the type-printing code,
which may want to resolve types, from the debug-reading code seems like
a bad idea.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 9/9] gdb: remove some uses of LA_PRINT_STRING
  2020-11-20 11:55 ` [PATCH 9/9] gdb: remove some uses of LA_PRINT_STRING Andrew Burgess
@ 2020-12-10 20:51   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2020-12-10 20:51 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> In the remaining 3 uses it is harder to know if the correct thing is
Andrew> to call printstr on the current language, or on a specific language.
Andrew> Currently obviously, we always call on the current language (as that's
Andrew> what LA_PRINT_STRING does), and clearly this behaviour is good enough
Andrew> right now, but is it "right"?  I've left them for now and will give
Andrew> them more thought in the future.

I didn't look to see what is left, or dig into this deeply at all, but I
wanted to mention: it was a relatively common thing for other languages
to depend on the C value-printer in particular, and so that printing
code was written in a funny style where it would sometimes make calls
via current_language to pick up the behavior of that other language in
some cases.  These days that would be better expressed by inheritance,
though I realize of course this would be toward the end, and not the
beginning, of the refactorings.  (Or even not done at all if possible.)

thanks,
Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/9] Further language class related changes
  2020-12-10 16:26 ` [PATCH 0/9] Further language class related changes Andrew Burgess
@ 2020-12-10 20:51   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2020-12-10 20:51 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

Andrew> Unless someone shouts out I plan to push this series in the next few
Andrew> days.

It all looks good to me.  Thank you for doing this.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2020-12-10 20:51 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-20 11:54 [PATCH 0/9] Further language class related changes Andrew Burgess
2020-11-20 11:54 ` [PATCH 1/9] gdb: delete unused function print_char_chars Andrew Burgess
2020-11-20 11:54 ` [PATCH 2/9] gdb: avoid accessing global C++ language implementation functions Andrew Burgess
2020-12-10 20:47   ` Tom Tromey
2020-11-20 11:54 ` [PATCH 3/9] gdb: rename c_printchar as language_defn::printchar Andrew Burgess
2020-11-20 11:54 ` [PATCH 4/9] gdb: remove LA_EMIT_CHAR macro Andrew Burgess
2020-11-20 11:55 ` [PATCH 5/9] gdb: move go_language class declaration into header file Andrew Burgess
2020-11-20 11:55 ` [PATCH 6/9] gdb: move pascal_language into p-lang.h Andrew Burgess
2020-11-20 11:55 ` [PATCH 7/9] gdb/objc: fix bug in objc_language::opcode_print_table Andrew Burgess
2020-11-20 11:55 ` [PATCH 8/9] gdb: move rust_language into rust-lang.h Andrew Burgess
2020-11-20 11:55 ` [PATCH 9/9] gdb: remove some uses of LA_PRINT_STRING Andrew Burgess
2020-12-10 20:51   ` Tom Tromey
2020-12-10 16:26 ` [PATCH 0/9] Further language class related changes Andrew Burgess
2020-12-10 20:51   ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).