Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/3 v4] gdb: Make printing enum types prettier
@ 2025-11-26 12:02 Daniel Knezevic
  2025-11-26 12:02 ` [PATCH 1/3] gdb: Move logic for printing enums to a helper function Daniel Knezevic
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Daniel Knezevic @ 2025-11-26 12:02 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey, Pedro Alves, Simon Marchi, Daniel Knezevic

This is v4 of:
  https://inbox.sourceware.org/gdb-patches/20251124132726.325366-1-daniel.knezevic@htecgroup.com/

Patch 1:
- A preparation patch, as suggested by Simon, that moves logic for printing
  enums to a helper function.

Patch 2:
- Updates tests to use multi_line as a preparation step for future changes
  related to enum printing.
  
Patch 3:
- Implements the new way of printing enums and updates tests using enums.
- I tried to reduce the number of print calls to minimum by using fprintf_styled
  function. When printing <variable name> = <value> two print calls are
  used. The reason for this is maintain printing in the right style (keep the
  same color scheme as before). The first fprintf_styled prints a colored
  (styled) variable name, then the gdb_printf prints out the value in default
  color.


Daniel Knezevic (3):
  gdb: Move logic for printing enums to a helper function
  gdb: Replace \r\n with multi_line to make tests more readable
  gdb: Make printing enum types prettier.

 gdb/c-typeprint.c                             | 151 +++++++-------
 gdb/testsuite/gdb.base/call-sc.exp            |  11 +-
 gdb/testsuite/gdb.base/ctf-ptype.exp          | 181 ++++++++++++++---
 gdb/testsuite/gdb.base/ptype.exp              | 186 +++++++++++++++---
 .../gdb.base/whatis-ptype-typedefs.exp        |   8 +-
 gdb/testsuite/gdb.cp/classes.exp              |  27 ++-
 gdb/testsuite/gdb.cp/empty-enum.exp           |  24 ++-
 gdb/testsuite/gdb.cp/enum-class.exp           |   6 +-
 gdb/testsuite/gdb.cp/nested-types.exp         |   6 +-
 gdb/testsuite/gdb.dwarf2/enum-type.exp        |  14 +-
 gdb/testsuite/gdb.xml/tdesc-regs.exp          |  39 +++-
 gdb/testsuite/lib/cp-support.exp              |  39 +++-
 12 files changed, 529 insertions(+), 163 deletions(-)

-- 
2.43.0

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

* [PATCH 1/3] gdb: Move logic for printing enums to a helper function
  2025-11-26 12:02 [PATCH 0/3 v4] gdb: Make printing enum types prettier Daniel Knezevic
@ 2025-11-26 12:02 ` Daniel Knezevic
  2025-11-26 12:03 ` [PATCH 2/3] gdb: Replace \r\n with multi_line to make tests more readable Daniel Knezevic
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Daniel Knezevic @ 2025-11-26 12:02 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey, Pedro Alves, Simon Marchi, Daniel Knezevic

---
 gdb/c-typeprint.c | 151 +++++++++++++++++++++++++---------------------
 1 file changed, 81 insertions(+), 70 deletions(-)

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 1dab82135d0..9e39c3d9b77 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -1292,6 +1292,83 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
     }
 }
 
+/* Helper for 'c_type_print_base' that handles enums.
+   For a description of the arguments, see 'c_type_print_base'.  */
+
+static void
+c_type_print_base_enum (struct type *type, struct ui_file *stream,
+			int show, int level,
+			enum language language,
+			const struct type_print_options *flags,
+			struct print_offset_data *podata)
+{
+  c_type_print_modifier (type, stream, 0, 1, language);
+  gdb_printf (stream, "enum ");
+  if (type->is_declared_class ())
+    gdb_printf (stream, "class ");
+  /* Print the tag name if it exists.
+     The aCC compiler emits a spurious
+     "{unnamed struct}"/"{unnamed union}"/"{unnamed enum}"
+     tag for unnamed struct/union/enum's, which we don't
+     want to print.  */
+  if (type->name () != NULL
+      && !startswith (type->name (), "{unnamed"))
+    {
+      print_name_maybe_canonical (type->name (), flags, stream);
+      if (show > 0)
+	gdb_puts (" ", stream);
+    }
+
+  stream->wrap_here (4);
+  if (show < 0)
+    {
+      /* If we just printed a tag name, no need to print anything
+	 else.  */
+      if (type->name () == NULL)
+	gdb_printf (stream, "{...}");
+    }
+  else if (show > 0 || type->name () == NULL)
+    {
+      LONGEST lastval = 0;
+
+      /* We can't handle this case perfectly, as DWARF does not
+	 tell us whether or not the underlying type was specified
+	 in the source (and other debug formats don't provide this
+	 at all).  We choose to print the underlying type, if it
+	 has a name, when in C++ on the theory that it's better to
+	 print too much than too little; but conversely not to
+	 print something egregiously outside the current
+	 language's syntax.  */
+      if (language == language_cplus && type->target_type () != NULL)
+	{
+	  struct type *underlying = check_typedef (type->target_type ());
+
+	  if (underlying->name () != NULL)
+	    gdb_printf (stream, ": %s ", underlying->name ());
+	}
+
+      gdb_printf (stream, "{");
+      int len = type->num_fields ();
+      for (int i = 0; i < len; i++)
+	{
+	  QUIT;
+	  if (i)
+	    gdb_printf (stream, ", ");
+	  stream->wrap_here (4);
+	  fputs_styled (type->field (i).name (),
+			variable_name_style.style (), stream);
+	  if (lastval != type->field (i).loc_enumval ())
+	    {
+	      gdb_printf (stream, " = %s",
+			  plongest (type->field (i).loc_enumval ()));
+	      lastval = type->field (i).loc_enumval ();
+	    }
+	  lastval++;
+	}
+      gdb_printf (stream, "}");
+    }
+}
+
 /* Print the name of the type (or the ultimate pointer target,
    function value or array element), or the description of a structure
    or union.
@@ -1317,9 +1394,6 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
 		     const struct type_print_options *flags,
 		     struct print_offset_data *podata)
 {
-  int i;
-  int len;
-
   QUIT;
 
   if (type == NULL)
@@ -1399,71 +1473,8 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
       break;
 
     case TYPE_CODE_ENUM:
-      c_type_print_modifier (type, stream, 0, 1, language);
-      gdb_printf (stream, "enum ");
-      if (type->is_declared_class ())
-	gdb_printf (stream, "class ");
-      /* Print the tag name if it exists.
-	 The aCC compiler emits a spurious
-	 "{unnamed struct}"/"{unnamed union}"/"{unnamed enum}"
-	 tag for unnamed struct/union/enum's, which we don't
-	 want to print.  */
-      if (type->name () != NULL
-	  && !startswith (type->name (), "{unnamed"))
-	{
-	  print_name_maybe_canonical (type->name (), flags, stream);
-	  if (show > 0)
-	    gdb_puts (" ", stream);
-	}
-
-      stream->wrap_here (4);
-      if (show < 0)
-	{
-	  /* If we just printed a tag name, no need to print anything
-	     else.  */
-	  if (type->name () == NULL)
-	    gdb_printf (stream, "{...}");
-	}
-      else if (show > 0 || type->name () == NULL)
-	{
-	  LONGEST lastval = 0;
-
-	  /* We can't handle this case perfectly, as DWARF does not
-	     tell us whether or not the underlying type was specified
-	     in the source (and other debug formats don't provide this
-	     at all).  We choose to print the underlying type, if it
-	     has a name, when in C++ on the theory that it's better to
-	     print too much than too little; but conversely not to
-	     print something egregiously outside the current
-	     language's syntax.  */
-	  if (language == language_cplus && type->target_type () != NULL)
-	    {
-	      struct type *underlying = check_typedef (type->target_type ());
-
-	      if (underlying->name () != NULL)
-		gdb_printf (stream, ": %s ", underlying->name ());
-	    }
-
-	  gdb_printf (stream, "{");
-	  len = type->num_fields ();
-	  for (i = 0; i < len; i++)
-	    {
-	      QUIT;
-	      if (i)
-		gdb_printf (stream, ", ");
-	      stream->wrap_here (4);
-	      fputs_styled (type->field (i).name (),
-			    variable_name_style.style (), stream);
-	      if (lastval != type->field (i).loc_enumval ())
-		{
-		  gdb_printf (stream, " = %s",
-			      plongest (type->field (i).loc_enumval ()));
-		  lastval = type->field (i).loc_enumval ();
-		}
-	      lastval++;
-	    }
-	  gdb_printf (stream, "}");
-	}
+      c_type_print_base_enum (type, stream, show, level,
+			      language, flags, podata);
       break;
 
     case TYPE_CODE_FLAGS:
@@ -1492,8 +1503,8 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
 			      level + 4, "",
 			      metadata_style.style ().ptr (), nullptr);
 	      }
-	    len = type->num_fields ();
-	    for (i = 0; i < len; i++)
+	    int len = type->num_fields ();
+	    for (int i = 0; i < len; i++)
 	      {
 		QUIT;
 		print_spaces (level + 4, stream);
-- 
2.43.0

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

* [PATCH 2/3] gdb: Replace \r\n with multi_line to make tests more readable
  2025-11-26 12:02 [PATCH 0/3 v4] gdb: Make printing enum types prettier Daniel Knezevic
  2025-11-26 12:02 ` [PATCH 1/3] gdb: Move logic for printing enums to a helper function Daniel Knezevic
@ 2025-11-26 12:03 ` Daniel Knezevic
  2025-11-26 12:43   ` Andreas Schwab
  2025-11-26 12:03 ` [PATCH 3/3] gdb: Make printing enum types prettier Daniel Knezevic
  2025-12-01 20:23 ` [PATCH 0/3 v4] " Tom Tromey
  3 siblings, 1 reply; 6+ messages in thread
From: Daniel Knezevic @ 2025-11-26 12:03 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey, Pedro Alves, Simon Marchi, Daniel Knezevic

---
 gdb/testsuite/gdb.base/ctf-ptype.exp | 105 ++++++++++++++++++++-----
 gdb/testsuite/gdb.base/ptype.exp     | 112 ++++++++++++++++++++++-----
 gdb/testsuite/gdb.xml/tdesc-regs.exp |  34 ++++++--
 3 files changed, 206 insertions(+), 45 deletions(-)

diff --git a/gdb/testsuite/gdb.base/ctf-ptype.exp b/gdb/testsuite/gdb.base/ctf-ptype.exp
index 8baefdc005e..30f333744de 100644
--- a/gdb/testsuite/gdb.base/ctf-ptype.exp
+++ b/gdb/testsuite/gdb.base/ctf-ptype.exp
@@ -59,7 +59,16 @@ gdb_test_multiple "ptype red1" "ptype unnamed enumeration member" {
 # Here and elsewhere, we accept
 # "long", "long int", or "int" for long variables (whatis.exp already
 # has an XFAIL for "int" (Sun cc bug), so no need to fail it here).
-gdb_test "ptype struct t_struct" "type = struct t_struct \{.*\[\r\n\]    (unsigned |)char v_char_member;.*\[\r\n\]    (short|short int) v_short_member;.*\[\r\n\]    int v_int_member;.*\[\r\n\]    (long|long int|int) v_long_member;.*\[\r\n\]    float v_float_member;.*\[\r\n\]    double v_double_member;.*\[\r\n\]\}.*" "ptype structure"
+gdb_test "ptype struct t_struct" \
+    [multi_line \
+	"type = struct t_struct {" \
+	"    (unsigned |)char v_char_member;" \
+	"    (short|short int) v_short_member;" \
+	"    int v_int_member;" \
+	"    (long|long int|int) v_long_member;" \
+	"    float v_float_member;" \
+	"    double v_double_member;" \
+	"}"] "ptype structure"
 
 
 # Test the equivalence between '.' and '->' for struct member references.
@@ -77,12 +86,27 @@ if {[gdb_test "ptype v_t_struct_p->v_float_member"	"type = float"] < 0} {
     return -1
 }
 
-gdb_test "ptype struct link" "type = struct link \{\[\r\n\]+\[ \t\]+struct link \\*next;\[\r\n\]+\[ \t\]+struct link \\*\\(\\*linkfunc\\)\\((struct link \\*, int|void|)\\);\[\r\n\]+\[ \t\]+struct t_struct stuff.3.;\[\r\n\]+\}.*" "ptype linked list structure"
+gdb_test "ptype struct link" \
+    [multi_line \
+	"type = struct link {" \
+	"    struct link \\*next;" \
+	"    struct link \\*\\(\\*linkfunc\\)\\((struct link \\*, int|void|)\\);" \
+	"    struct t_struct stuff.3.;" \
+	"}"] "ptype linked list structure"
 
 #
 # test ptype command with unions
 #
-gdb_test "ptype union t_union" "type = union t_union \{.*\[\r\n\]    (unsigned |)char v_char_member;.*\[\r\n\]    (short|short int) v_short_member;.*\[\r\n\]    int v_int_member;.*\[\r\n\]    (long|long int|int) v_long_member;.*\[\r\n\]    float v_float_member;.*\[\r\n\]    double v_double_member;.*\[\r\n\]\}.*" "ptype union"
+gdb_test "ptype union t_union" \
+    [multi_line \
+	"type = union t_union {" \
+	"    (unsigned |)char v_char_member;" \
+	"    (short|short int) v_short_member;" \
+	"    int v_int_member;" \
+	"    (long|long int|int) v_long_member;" \
+	"    float v_float_member;" \
+	"    double v_double_member;" \
+	"}"] "ptype union"
 
 #
 # test ptype command with enums
@@ -179,33 +203,69 @@ gdb_test "ptype v_int" "type = int.*" "ptype int"
 #
 # test ptype command with nested structure and union
 #
-gdb_test "ptype struct outer_struct" "type = struct outer_struct \{.*\[\r\n\]+\
-.*int outer_int;.*\[\r\n\]+\
-.*(struct|) inner_struct inner_struct_instance;.*\[\r\n\]+\
-.*(union|) inner_union inner_union_instance;.*\[\r\n\]+\
-.*(long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype outer structure"
-
-gdb_test "ptype struct inner_struct" "type = struct inner_struct \{.*\[\r\n\]    int inner_int;.*\[\r\n\]    (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype inner structure"
-
-gdb_test "ptype union inner_union" "type = union inner_union \{.*\[\r\n\]    int inner_union_int;.*\[\r\n\]    (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype inner union"
-
-gdb_test "ptype nested_su" "type = struct outer_struct \{.*\[\r\n\]    int outer_int;.*\[\r\n\]    (struct |)inner_struct inner_struct_instance;.*\[\r\n\]    (union |)inner_union inner_union_instance;.*\[\r\n\]    (long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype nested structure"
+gdb_test "ptype struct outer_struct" \
+    [multi_line \
+	"type = struct outer_struct {" \
+	"    int outer_int;" \
+	"    (struct|) inner_struct inner_struct_instance;" \
+	"    (union|) inner_union inner_union_instance;" \
+	"    (long|long int|int) outer_long;" \
+	"}"] "ptype outer structure"
+
+gdb_test "ptype struct inner_struct" \
+    [multi_line \
+	"type = struct inner_struct {" \
+	"    int inner_int;" \
+	"    (long|long int|int) inner_long;" \
+	"}"] "ptype inner structure"
+
+gdb_test "ptype union inner_union" \
+    [multi_line \
+	"type = union inner_union {" \
+	"    int inner_union_int;" \
+	"    (long|long int|int) inner_union_long;" \
+	"}"] "ptype inner union"
+
+gdb_test "ptype nested_su" \
+    [multi_line \
+	"type = struct outer_struct {" \
+	"    int outer_int;" \
+	"    (struct |)inner_struct inner_struct_instance;" \
+	"    (union |)inner_union inner_union_instance;" \
+	"    (long|long int|int) outer_long;" \
+	"}"] "ptype nested structure"
 
 gdb_test "ptype nested_su.outer_int" "type = int.*" "ptype outer int"
 
-gdb_test "ptype nested_su.inner_struct_instance" "type = struct inner_struct \{.*\[\r\n\]    int inner_int;.*\[\r\n\]    (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype nested structure #2"
+gdb_test "ptype nested_su.inner_struct_instance" \
+    [multi_line \
+	"type = struct inner_struct {" \
+	"    int inner_int;" \
+	"    (long|long int|int) inner_long;" \
+	"}"] "ptype nested structure #2"
 
 gdb_test "ptype nested_su.inner_struct_instance.inner_int" "type = int.*" "ptype inner int"
 
-gdb_test "ptype nested_su.inner_union_instance" "type = union inner_union \{.*\[\r\n\]    int inner_union_int;.*\[\r\n\]    (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype nested union"
+gdb_test "ptype nested_su.inner_union_instance" \
+    [multi_line \
+	"type = union inner_union {" \
+	"    int inner_union_int;" \
+	"    (long|long int|int) inner_union_long;" \
+	"}"] "ptype nested union"
 
 # Print the type description of variable the_highest, and verify that
 # the type description for the fields whose type is anonymous are
 # correctly printed (at nesting level 1 and 2).
 
 gdb_test "ptype the_highest" \
-	 "type = struct highest \{.*\[\r\n\] *int a;.*\[\r\n\] *struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{\.\.\.\} anonymous_level_2;.*\[\r\n\] *\} anonymous_level_1;.*\[\r\n\]}.*" \
-	 "ptype the_highest"
+    [multi_line \
+	"type = struct highest {" \
+	"    int a;" \
+	"    struct {" \
+	"        int b;" \
+	"        struct \{\.\.\.\} anonymous_level_2;" \
+	"    \} anonymous_level_1;" \
+	"}"] "ptype the_highest"
 
 # Print the type descrption for one of the fields of variable the_highest.
 # The purpose is to verify that the type of a field that was printed above
@@ -213,8 +273,13 @@ gdb_test "ptype the_highest" \
 # nesting level is now one level less).
 
 gdb_test "ptype the_highest.anonymous_level_1" \
-	 "type = struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{.*\[\r\n\] *int c;.*\[\r\n\] *\} anonymous_level_2;.*\[\r\n\]}.*" \
-	 "ptype the_highest.anonymous_level_1"
+    [multi_line \
+	"type = struct {" \
+	"    int b;" \
+	"    struct {" \
+	"        int c;" \
+	"    \} anonymous_level_2;" \
+	"}"] "ptype the_highest.anonymous_level_1"
 
 # Print the type of the identifier ID, and check the response:
 # - Expect to see PROTOTYPED as the type.  PROTOTYPED is not a regular
diff --git a/gdb/testsuite/gdb.base/ptype.exp b/gdb/testsuite/gdb.base/ptype.exp
index cf28aea2f51..3335950e93e 100644
--- a/gdb/testsuite/gdb.base/ptype.exp
+++ b/gdb/testsuite/gdb.base/ptype.exp
@@ -51,7 +51,16 @@ gdb_test_multiple "ptype red1" "ptype unnamed enumeration member" {
 # Here and elsewhere, we accept
 # "long", "long int", or "int" for long variables (whatis.exp already
 # has an XFAIL for "int" (Sun cc bug), so no need to fail it here).
-gdb_test "ptype struct t_struct" "type = struct t_struct \{.*\[\r\n\]    (unsigned |)char v_char_member;.*\[\r\n\]    (short|short int) v_short_member;.*\[\r\n\]    int v_int_member;.*\[\r\n\]    (long|long int|int) v_long_member;.*\[\r\n\]    float v_float_member;.*\[\r\n\]    double v_double_member;.*\[\r\n\]\}.*" "ptype structure"
+gdb_test "ptype struct t_struct" \
+    [multi_line \
+	"type = struct t_struct {" \
+	"    (unsigned |)char v_char_member;" \
+	"    (short|short int) v_short_member;" \
+	"    int v_int_member;" \
+	"    (long|long int|int) v_long_member;" \
+	"    float v_float_member;" \
+	"    double v_double_member;" \
+	"}"] "ptype structure"
 
 
 # Test the equivalence between '.' and '->' for struct member references.
@@ -73,16 +82,37 @@ if {[gdb_test "ptype v_t_struct_p->v_float_member" "type = float"] < 0} {
 # IBM's xlc puts out bogus stabs--the stuff field is type 42,
 # which isn't defined.
 
-gdb_test "ptype struct link" "type = struct link \{\[\r\n\]+\[ \t\]+struct link \\*next;\[\r\n\]+\[ \t\]+struct link \\*\\(\\*linkfunc\\)\\((struct link \\*, int|void|)\\);\[\r\n\]+\[ \t\]+struct t_struct stuff.1..2..3.;\[\r\n\]+\}.*" "ptype linked list structure"
+gdb_test "ptype struct link" \
+    [multi_line \
+	"type = struct link {" \
+	"    struct link \\*next;" \
+	"    struct link \\*\\(\\*linkfunc\\)\\((struct link \\*, int|void|)\\);" \
+	"    struct t_struct stuff.1..2..3.;" \
+	"}"] "ptype linked list structure"
 
 #
 # test ptype command with unions
 #
-gdb_test "ptype union t_union" "type = union t_union \{.*\[\r\n\]    (unsigned |)char v_char_member;.*\[\r\n\]    (short|short int) v_short_member;.*\[\r\n\]    int v_int_member;.*\[\r\n\]    (long|long int|int) v_long_member;.*\[\r\n\]    float v_float_member;.*\[\r\n\]    double v_double_member;.*\[\r\n\]\}.*" "ptype union"
+gdb_test "ptype union t_union" \
+    [multi_line \
+	"type = union t_union {" \
+	"    (unsigned |)char v_char_member;" \
+	"    (short|short int) v_short_member;" \
+	"    int v_int_member;" \
+	"    (long|long int|int) v_long_member;" \
+	"    float v_float_member;" \
+	"    double v_double_member;" \
+	"}"] "ptype union"
 
 # IBM's xlc puts out bogus stabs--the stuff field is type 42,
 # which isn't defined.
-gdb_test "ptype union tu_link" "type = union tu_link \{\[\r\n\]+\[ \t\]+struct link \\*next;\[\r\n\]+\[ \t\]+struct link \\*\\(\\*linkfunc\\)\\((struct link \\*, int|void|)\\);\[\r\n\]+\[ \t\]+struct t_struct stuff.1..2..3.;\[\r\n\]+\}.*" "ptype linked list union"
+gdb_test "ptype union tu_link" \
+    [multi_line \
+	"type = union tu_link {" \
+	"    struct link \\*next;" \
+	"    struct link \\*\\(\\*linkfunc\\)\\((struct link \\*, int|void|)\\);" \
+	"    struct t_struct stuff.1..2..3.;" \
+	"}"] "ptype linked list union"
 
 #
 # test ptype command with enums
@@ -472,32 +502,69 @@ gdb_test "ptype pv_char_array" "type = (|unsigned )char \\(\\*\\)\\\[0?\\\]"
 #
 # test ptype command with nested structure and union
 #
-gdb_test "ptype struct outer_struct" "type = struct outer_struct \{.*\[\r\n\]+\
-.*int outer_int;.*\[\r\n\]+\
-.*(struct|) inner_struct inner_struct_instance;.*\[\r\n\]+\
-.*(union|) inner_union inner_union_instance;.*\[\r\n\]+\
-.*(long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype outer structure"
-
-gdb_test "ptype struct inner_struct" "type = struct inner_struct \{.*\[\r\n\]    int inner_int;.*\[\r\n\]    (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype inner structure"
-
-gdb_test "ptype union inner_union" "type = union inner_union \{.*\[\r\n\]    int inner_union_int;.*\[\r\n\]    (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype inner union"
-
-gdb_test "ptype nested_su" "type = struct outer_struct \{.*\[\r\n\]    int outer_int;.*\[\r\n\]    (struct |)inner_struct inner_struct_instance;.*\[\r\n\]    (union |)inner_union inner_union_instance;.*\[\r\n\]    (long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype nested structure"
+gdb_test "ptype struct outer_struct" \
+    [multi_line \
+	"type = struct outer_struct {" \
+	"    int outer_int;" \
+	"    (struct|) inner_struct inner_struct_instance;" \
+	"    (union|) inner_union inner_union_instance;" \
+	"    (long|long int|int) outer_long;" \
+	"}"] "ptype outer structure"
+
+gdb_test "ptype struct inner_struct" \
+    [multi_line \
+	"type = struct inner_struct {" \
+	"    int inner_int;" \
+	"    (long|long int|int) inner_long;" \
+	"}"] "ptype inner structure"
+
+gdb_test "ptype union inner_union" \
+    [multi_line \
+	"type = union inner_union {" \
+	"    int inner_union_int;" \
+	"    (long|long int|int) inner_union_long;" \
+	"}"] "ptype inner union"
+
+gdb_test "ptype nested_su" \
+    [multi_line \
+	"type = struct outer_struct {" \
+	"    int outer_int;" \
+	"    (struct |)inner_struct inner_struct_instance;" \
+	"    (union |)inner_union inner_union_instance;" \
+	"    (long|long int|int) outer_long;" \
+	"}"] "ptype nested structure"
 
 gdb_test "ptype nested_su.outer_int" "type = int.*" "ptype outer int"
 
-gdb_test "ptype nested_su.inner_struct_instance" "type = struct inner_struct \{.*\[\r\n\]    int inner_int;.*\[\r\n\]    (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype nested structure #2"
+gdb_test "ptype nested_su.inner_struct_instance" \
+    [multi_line \
+	"type = struct inner_struct {" \
+	"    int inner_int;" \
+	"    (long|long int|int) inner_long;" \
+	"}"] "ptype nested structure #2"
 
 gdb_test "ptype nested_su.inner_struct_instance.inner_int" "type = int.*" "ptype inner int"
 
-gdb_test "ptype nested_su.inner_union_instance" "type = union inner_union \{.*\[\r\n\]    int inner_union_int;.*\[\r\n\]    (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype nested union"
+gdb_test "ptype nested_su.inner_union_instance" \
+    [multi_line \
+	"type = union inner_union {" \
+	"    int inner_union_int;" \
+	"    (long|long int|int) inner_union_long;" \
+	"}"] "ptype nested union"
 
 # Print the type description of variable the_highest, and verify that
 # the type description for the fields whose type is anonymous are
 # correctly printed (at nesting level 1 and 2).
 
 gdb_test "ptype the_highest" \
-	 "type = struct highest \{.*\[\r\n\] *int a;.*\[\r\n\] *struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{\.\.\.\} anonymous_level_2;.*\[\r\n\] *\} anonymous_level_1;.*\[\r\n\]}.*"
+    [multi_line \
+	"type = struct highest {" \
+	"    int a;" \
+	"    struct {" \
+	"        int b;" \
+	"        struct \{\.\.\.\} anonymous_level_2;" \
+	"    \} anonymous_level_1;" \
+	"}"]
 
 # Print the type descrption for one of the fields of variable the_highest.
 # The purpose is to verify that the type of a field that was printed above
@@ -505,8 +572,13 @@ gdb_test "ptype the_highest" \
 # nesting level is now one level less).
 
 gdb_test "ptype the_highest.anonymous_level_1" \
-	 "type = struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{.*\[\r\n\] *int c;.*\[\r\n\] *\} anonymous_level_2;.*\[\r\n\]}.*" \
-	 "ptype the_highest.anonymous_level_1"
+    [multi_line \
+	"type = struct {" \
+	"    int b;" \
+	"    struct {" \
+	"        int c;" \
+	"    \} anonymous_level_2;" \
+	"}"] "ptype the_highest.anonymous_level_1"
 
 get_debug_format
 
diff --git a/gdb/testsuite/gdb.xml/tdesc-regs.exp b/gdb/testsuite/gdb.xml/tdesc-regs.exp
index fa9b5b71310..63f5ebc90d8 100644
--- a/gdb/testsuite/gdb.xml/tdesc-regs.exp
+++ b/gdb/testsuite/gdb.xml/tdesc-regs.exp
@@ -179,17 +179,41 @@ gdb_test "ptype \$extrareg" "type = (int32_t|int|long|long long)"
 gdb_test "ptype \$uintreg" "type = uint32_t"
 gdb_test "ptype \$vecreg" "type = int8_t __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
 gdb_test "ptype \$unionreg" \
-    "type = union vecint {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}"
+    [multi_line \
+	"type = union vecint {" \
+	"    v4int8 v4;" \
+	"    v2int16 v2;" \
+	"}"]
 gdb_test "ptype \$unionreg.v4" "type = int8_t __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
 gdb_test "ptype \$structreg" \
-    "type = struct struct1 {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}"
+    [multi_line \
+	"type = struct struct1 {" \
+	"    v4int8 v4;" \
+	"    v2int16 v2;" \
+	"}"]
 gdb_test "ptype \$structreg.v4" "type = int8_t __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
 gdb_test "ptype \$bitfields" \
-    "type = struct struct2 {\r\n *uint64_t f1 : 35;\r\n *uint64_t f2 : 1;\r\n}"
+    [multi_line \
+	"type = struct struct2 {" \
+	"    uint64_t f1 : 35;" \
+	"    uint64_t f2 : 1;" \
+	"}"]
 gdb_test "ptype \$flags" \
-    "type = flag flags {\r\n *bool X @0;\r\n *uint32_t Y @2;\r\n}"
+    [multi_line \
+	"type = flag flags {" \
+	"    bool X @0;" \
+	"    uint32_t Y @2;" \
+	"}"]
 gdb_test "ptype \$mixed_flags" \
-    "type = flag mixed_flags {\r\n *bool A @0;\r\n *uint32_t B @1-3;\r\n *bool C @4;\r\n *uint32_t D @5;\r\n *uint32_t @6-7;\r\n *enum Z_values {yes = 1, no = 0, maybe = 2, so} Z @8-9;\r\n}"
+    [multi_line \
+	"type = flag mixed_flags {" \
+	"    bool A @0;" \
+	"    uint32_t B @1-3;" \
+	"    bool C @4;" \
+	"    uint32_t D @5;" \
+	"    uint32_t @6-7;" \
+	"    enum Z_values {yes = 1, no = 0, maybe = 2, so} Z @8-9;" \
+	"}"]
 # Reggroups should have at least general and the extra foo group
 gdb_test "maintenance print reggroups" \
     "Group\[ \t\]+Type\[ \t\]+\r\n.*general\[ \t\]+user\[ \t\]+\r\n.*foo\[ \t\]+user\[ \t\]+"
-- 
2.43.0

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

* [PATCH 3/3] gdb: Make printing enum types prettier.
  2025-11-26 12:02 [PATCH 0/3 v4] gdb: Make printing enum types prettier Daniel Knezevic
  2025-11-26 12:02 ` [PATCH 1/3] gdb: Move logic for printing enums to a helper function Daniel Knezevic
  2025-11-26 12:03 ` [PATCH 2/3] gdb: Replace \r\n with multi_line to make tests more readable Daniel Knezevic
@ 2025-11-26 12:03 ` Daniel Knezevic
  2025-12-01 20:23 ` [PATCH 0/3 v4] " Tom Tromey
  3 siblings, 0 replies; 6+ messages in thread
From: Daniel Knezevic @ 2025-11-26 12:03 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey, Pedro Alves, Simon Marchi, Daniel Knezevic

Update printing of enum types to follow the same formatting
conventions as for structs resulting in more readable output.
Now that horizontal space is less of an issue enum values are
always printed.
Empty enums are now printed with an added "<no enum values>"
message.

Example of printing an enum with default values:
enum class TestEnum {A, B, C, D};

(gdb) ptype TestEnum
type = enum class TestEnum : int {
    TestEnum::A = 0,
    TestEnum::B = 1,
    TestEnum::C = 2,
    TestEnum::D = 3
}

Example of printing an empty enum:
enum class TestEnum {};

(gdb) ptype TestEnum
type = enum class TestEnum : int {
    <no enum values>
}

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19294
---
 gdb/c-typeprint.c                             | 28 +++----
 gdb/testsuite/gdb.base/call-sc.exp            | 11 ++-
 gdb/testsuite/gdb.base/ctf-ptype.exp          | 76 ++++++++++++++++---
 gdb/testsuite/gdb.base/ptype.exp              | 76 ++++++++++++++++---
 .../gdb.base/whatis-ptype-typedefs.exp        |  8 +-
 gdb/testsuite/gdb.cp/classes.exp              | 27 ++++++-
 gdb/testsuite/gdb.cp/empty-enum.exp           | 24 +++++-
 gdb/testsuite/gdb.cp/enum-class.exp           |  6 +-
 gdb/testsuite/gdb.cp/nested-types.exp         |  6 +-
 gdb/testsuite/gdb.dwarf2/enum-type.exp        | 14 +++-
 gdb/testsuite/gdb.xml/tdesc-regs.exp          |  7 +-
 gdb/testsuite/lib/cp-support.exp              | 39 +++++++---
 12 files changed, 258 insertions(+), 64 deletions(-)

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 9e39c3d9b77..4dba9222066 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -1329,8 +1329,6 @@ c_type_print_base_enum (struct type *type, struct ui_file *stream,
     }
   else if (show > 0 || type->name () == NULL)
     {
-      LONGEST lastval = 0;
-
       /* We can't handle this case perfectly, as DWARF does not
 	 tell us whether or not the underlying type was specified
 	 in the source (and other debug formats don't provide this
@@ -1347,25 +1345,27 @@ c_type_print_base_enum (struct type *type, struct ui_file *stream,
 	    gdb_printf (stream, ": %s ", underlying->name ());
 	}
 
-      gdb_printf (stream, "{");
+      gdb_printf (stream, "{\n");
       int len = type->num_fields ();
-      for (int i = 0; i < len; i++)
+      if (len == 0)
 	{
-	  QUIT;
-	  if (i)
-	    gdb_printf (stream, ", ");
-	  stream->wrap_here (4);
-	  fputs_styled (type->field (i).name (),
-			variable_name_style.style (), stream);
-	  if (lastval != type->field (i).loc_enumval ())
+	  fprintf_styled (stream, metadata_style.style (),
+			  "%*s<no enum values>", level + 4, "");
+	}
+      else
+	{
+	  for (int i = 0; i < len; i++)
 	    {
+	      QUIT;
+	      if (i != 0)
+		gdb_printf (stream, ",\n");
+	      fprintf_styled (stream, variable_name_style.style (),
+			      "%*s%s", level + 4, "", type->field (i).name ());
 	      gdb_printf (stream, " = %s",
 			  plongest (type->field (i).loc_enumval ()));
-	      lastval = type->field (i).loc_enumval ();
 	    }
-	  lastval++;
 	}
-      gdb_printf (stream, "}");
+      gdb_printf (stream, "\n%*s}", level, "");
     }
 }
 
diff --git a/gdb/testsuite/gdb.base/call-sc.exp b/gdb/testsuite/gdb.base/call-sc.exp
index 5f7cfe00c03..6f46ff2a67c 100644
--- a/gdb/testsuite/gdb.base/call-sc.exp
+++ b/gdb/testsuite/gdb.base/call-sc.exp
@@ -73,8 +73,17 @@ proc start_scalars_test { type } {
 	    set foo_t "$expect_out(1,string)"
 	    pass "$test (${foo_t})"
 	}
+	-re "type = enum .*\\{\r\n.*\r\n\\}\r\n$gdb_prompt $" {
+	    set foo_t "$expect_out(1,string)"
+	    pass "$test (${foo_t})"
+	}
+    }
+    gdb_test_multiple "ptype/r foo" "ptype foo; ${testfile}" {
+	-re "type = .*$gdb_prompt $" {
+	    set foo_t "$expect_out(1,string)"
+	    pass "$test (${foo_t})"
+	}
     }
-    gdb_test "ptype/r foo" "type = ${foo_t}" "ptype foo; ${testfile} $expect_out(1,string)"
 }
 
 
diff --git a/gdb/testsuite/gdb.base/ctf-ptype.exp b/gdb/testsuite/gdb.base/ctf-ptype.exp
index 30f333744de..2515ad5422c 100644
--- a/gdb/testsuite/gdb.base/ctf-ptype.exp
+++ b/gdb/testsuite/gdb.base/ctf-ptype.exp
@@ -42,13 +42,27 @@ gdb_load $binfile
 # with stabs compilers which fail to use a nameless stab (such as
 # pre-2.4.5 versions of gcc and most non-gcc compilers).
 
+
+set re1 [multi_line \
+    "type = enum primary1_tag {" \
+    "    red1 = 0," \
+    "    green1 = 1," \
+    "    blue1 = 2" \
+    "}.*$gdb_prompt $"]
+set re2 [multi_line \
+    "type = enum {" \
+    "    red1 = 0," \
+    "    green1 = 1," \
+    "    blue1 = 2" \
+    "}.*$gdb_prompt $"]
+
 gdb_test_multiple "ptype red1" "ptype unnamed enumeration member" {
-    -re "type = enum primary1_tag \{red1, green1, blue1\}.*$gdb_prompt $" {
+    -re $re1 {
 	# The workaround is in effect.  As this is a compiler, not GDB,
 	# bug, we'll make it a PASS but perhaps it should be an XFAIL.
 	pass "ptype unnamed enumeration member (worked around)"
     }
-    -re "type = enum \{red1, green1, blue1\}.*$gdb_prompt $" {
+    -re $re2 {
 	pass "ptype unnamed enumeration member"
     }
 }
@@ -112,15 +126,32 @@ gdb_test "ptype union t_union" \
 # test ptype command with enums
 #
 
-gdb_test "ptype primary" "type = enum .red, green, blue.*" "ptype unnamed enumeration"
+gdb_test "ptype primary" \
+    [multi_line \
+	"type = enum {" \
+	"    red = 0," \
+	"    green = 1," \
+	"    blue = 2" \
+	"}"] "ptype unnamed enumeration"
 
-gdb_test "ptype enum colors" "type = enum colors \{yellow, purple, pink\}.*" "ptype named enumeration"
+gdb_test "ptype enum colors" \
+    [multi_line \
+	"type = enum colors {" \
+	"    yellow = 0," \
+	"    purple = 1," \
+	"    pink = 2" \
+	"}"] "ptype named enumeration"
 
 
 #
 # test ptype command with enums as typedef
 #
-gdb_test "ptype boolean" "type = enum (boolean |)\{FALSE, TRUE\}.*" "ptype unnamed typedef'd enumeration"
+gdb_test "ptype boolean" \
+    [multi_line \
+	"type = enum (boolean |){" \
+	"    FALSE = 0," \
+	"    TRUE = 1" \
+	"}"] "ptype unnamed typedef'd enumeration"
 
 gdb_test "list -q main" ".*"
 
@@ -133,19 +164,44 @@ gdb_test "ptype t_union3" "type = union (t_union3 |)\{.*
  *double v_double_member;.*
  *int v_int_member;.*\}" "printing typedef'd union"
 
-gdb_test "ptype enum bvals" "type = enum bvals \{my_false, my_true\}.*" "ptype named typedef'd enumf'd enum"
+gdb_test "ptype enum bvals" \
+    [multi_line \
+	"type = enum bvals {" \
+	"    my_false = 0," \
+	"    my_true = 1" \
+	"}"] "ptype named typedef'd enumf'd enum"
 
 #
 # test ptype command with out-of-order enum values
 #
-gdb_test "ptype enum misordered" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype misordered enumeration"
+gdb_test "ptype enum misordered" \
+    [multi_line \
+	"type = enum misordered {" \
+	"    two = 2," \
+	"    one = 1," \
+	"    zero = 0," \
+	"    three = 3" \
+	"}"] "ptype misordered enumeration"
 
 #
 # test ptype command with a named enum's value
 #
-gdb_test "ptype three" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype named enumeration member"
-
-gdb_test "ptype red" "type = enum \{red, green, blue\}.*" "ptype unnamed enumeration member #2"
+gdb_test "ptype three" \
+    [multi_line \
+	"type = enum misordered {" \
+	"    two = 2," \
+	"    one = 1," \
+	"    zero = 0," \
+	"    three = 3" \
+	"}"] "ptype named enumeration member"
+
+gdb_test "ptype red" \
+    [multi_line \
+	"type = enum {" \
+	"    red = 0," \
+	"    green = 1," \
+	"    blue = 2" \
+	"}"] "ptype unnamed enumeration member #2"
 
 #
 # test ptype command with arrays
diff --git a/gdb/testsuite/gdb.base/ptype.exp b/gdb/testsuite/gdb.base/ptype.exp
index 3335950e93e..be2d5dedc63 100644
--- a/gdb/testsuite/gdb.base/ptype.exp
+++ b/gdb/testsuite/gdb.base/ptype.exp
@@ -34,13 +34,27 @@ set gcc_compiled [is_c_compiler_gcc]
 # with stabs compilers which fail to use a nameless stab (such as
 # pre-2.4.5 versions of gcc and most non-gcc compilers).
 
+
+set re1 [multi_line \
+    "type = enum primary1_tag {" \
+    "    red1 = 0," \
+    "    green1 = 1," \
+    "    blue1 = 2" \
+    "}.*$gdb_prompt $"]
+set re2 [multi_line \
+    "type = enum {" \
+    "    red1 = 0," \
+    "    green1 = 1," \
+    "    blue1 = 2" \
+    "}.*$gdb_prompt $"]
+
 gdb_test_multiple "ptype red1" "ptype unnamed enumeration member" {
-    -re "type = enum primary1_tag \{red1, green1, blue1\}.*$gdb_prompt $" {
+    -re $re1 {
 	# The workaround is in effect.  As this is a compiler, not GDB,
 	# bug, we'll make it a PASS but perhaps it should be an XFAIL.
 	pass "ptype unnamed enumeration member (worked around)"
     }
-    -re "type = enum \{red1, green1, blue1\}.*$gdb_prompt $" {
+    -re $re2 {
 	pass "ptype unnamed enumeration member"
     }
 }
@@ -118,15 +132,32 @@ gdb_test "ptype union tu_link" \
 # test ptype command with enums
 #
 
-gdb_test "ptype primary" "type = enum .red, green, blue.*" "ptype unnamed enumeration"
+gdb_test "ptype primary" \
+    [multi_line \
+	"type = enum {" \
+	"    red = 0," \
+	"    green = 1," \
+	"    blue = 2" \
+	"}"] "ptype unnamed enumeration"
 
-gdb_test "ptype enum colors" "type = enum colors \{yellow, purple, pink\}.*" "ptype named enumeration"
+gdb_test "ptype enum colors" \
+    [multi_line \
+	"type = enum colors {" \
+	"    yellow = 0," \
+	"    purple = 1," \
+	"    pink = 2" \
+	"}"] "ptype named enumeration"
 
 
 #
 # test ptype command with enums as typedef
 #
-gdb_test "ptype boolean" "type = enum (boolean |)\{FALSE, TRUE\}.*" "ptype unnamed typedef'd enumeration"
+gdb_test "ptype boolean" \
+    [multi_line \
+	"type = enum (boolean |){" \
+	"    FALSE = 0," \
+	"    TRUE = 1" \
+	"}"] "ptype unnamed typedef'd enumeration"
 
 # And check that whatis shows the name, not "enum {...}".
 # This probably fails for all DWARF 1 cases, so assume so for now. -fnf
@@ -157,19 +188,44 @@ gdb_test "ptype t_union3" "type = union (t_union3 |)\{.*
  *double v_double_member;.*
  *int v_int_member;.*\}" "printing typedef'd union"
 
-gdb_test "ptype enum bvals" "type = enum bvals \{my_false, my_true\}.*" "ptype named typedef'd enumf'd enum"
+gdb_test "ptype enum bvals" \
+    [multi_line \
+	"type = enum bvals {" \
+	"    my_false = 0," \
+	"    my_true = 1" \
+	"}"] "ptype named typedef'd enumf'd enum"
 
 #
 # test ptype command with out-of-order enum values
 #
-gdb_test "ptype enum misordered" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype misordered enumeration"
+gdb_test "ptype enum misordered" \
+    [multi_line \
+	"type = enum misordered {" \
+	"    two = 2," \
+	"    one = 1," \
+	"    zero = 0," \
+	"    three = 3" \
+	"}"] "ptype misordered enumeration"
 
 #
 # test ptype command with a named enum's value
 #
-gdb_test "ptype three" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype named enumeration member"
-
-gdb_test "ptype red" "type = enum \{red, green, blue\}.*" "ptype unnamed enumeration member #2"
+gdb_test "ptype three" \
+    [multi_line \
+	"type = enum misordered {" \
+	"    two = 2," \
+	"    one = 1," \
+	"    zero = 0," \
+	"    three = 3" \
+	"}"] "ptype named enumeration member"
+
+gdb_test "ptype red" \
+    [multi_line \
+	"type = enum {" \
+	"    red = 0," \
+	"    green = 1," \
+	"    blue = 2" \
+	"}"] "ptype unnamed enumeration member #2"
 
 #
 # test ptype command with basic C types
diff --git a/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp
index 744c6ee999e..8eec4470618 100644
--- a/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp
+++ b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp
@@ -103,10 +103,10 @@ set table {
     {"v_long_double_typedef"  "long_double_typedef"   "long double"}
     {"v_long_double_typedef2" "long_double_typedef2"  "long double"}
 
-    {"colors_typedef"     "(enum )?colors"   "enum colors( : unsigned int)? {red, green, blue}"}
-    {"colors_typedef2"    "colors_typedef"   "enum colors( : unsigned int)? {red, green, blue}"}
-    {"v_colors_typedef"   "colors_typedef"   "enum colors( : unsigned int)? {red, green, blue}"}
-    {"v_colors_typedef2"  "colors_typedef2"  "enum colors( : unsigned int)? {red, green, blue}"}
+    {"colors_typedef"     "(enum )?colors"   "enum colors( : unsigned int)? {.*red = 0,.* green = 1,.* blue = 2.*}"}
+    {"colors_typedef2"    "colors_typedef"   "enum colors( : unsigned int)? {.*red = 0,.* green = 1,.* blue = 2.*}"}
+    {"v_colors_typedef"   "colors_typedef"   "enum colors( : unsigned int)? {.*red = 0,.* green = 1,.* blue = 2.*}"}
+    {"v_colors_typedef2"  "colors_typedef2"  "enum colors( : unsigned int)? {.*red = 0,.* green = 1,.* blue = 2.*}"}
 
     {"func_ftype"         "void \\(void\\)"  "void \\(void\\)"}
     {"func_ftype2"        "func_ftype"       "void \\(void\\)"}
diff --git a/gdb/testsuite/gdb.cp/classes.exp b/gdb/testsuite/gdb.cp/classes.exp
index 64689c701e2..13195a08e4f 100644
--- a/gdb/testsuite/gdb.cp/classes.exp
+++ b/gdb/testsuite/gdb.cp/classes.exp
@@ -510,16 +510,37 @@ proc test_enums {} {
 
     # ptype on the enum member
 
+    set re1 [multi_line \
+	"type = enum ClassWithEnum::PrivEnum (: unsigned (int|short|char) )?{" \
+	"    ?(ClassWithEnum::)?red = 0," \
+	"    (ClassWithEnum::)?green = 1," \
+	"    (ClassWithEnum::)?blue = 2," \
+	"    (ClassWithEnum::)?yellow = 42" \
+	"?}$nl$gdb_prompt $"]
+    set re2 [multi_line \
+	"type = enum PrivEnum {" \
+	"    ?(ClassWithEnum::)?red = 0," \
+	"    (ClassWithEnum::)?green = 1," \
+	"    (ClassWithEnum::)?blue = 2," \
+	"    (ClassWithEnum::)?yellow = 42" \
+	"?}$nl$gdb_prompt $"]
+    set re3 [multi_line \
+	"type = enum {" \
+	"    ?red = 0," \
+	"    green = 1," \
+	"    blue = 2," \
+	"    yellow = 42" \
+	"?}$nl$gdb_prompt $"]
     gdb_test_multiple "ptype obj_with_enum.priv_enum" "ptype obj_with_enum.priv_enum" {
-	-re "type = enum ClassWithEnum::PrivEnum (: unsigned (int|short|char) )?\{ ?(ClassWithEnum::)?red, (ClassWithEnum::)?green, (ClassWithEnum::)?blue, (ClassWithEnum::)?yellow = 42 ?\}$nl$gdb_prompt $" {
+	-re $re1 {
 	    pass "ptype obj_with_enum.priv_enum"
 	}
-	-re "type = enum PrivEnum \{ ?(ClassWithEnum::)?red, (ClassWithEnum::)?green, (ClassWithEnum::)?blue, (ClassWithEnum::)?yellow = 42 ?\}$nl$gdb_prompt $" {
+	-re $re2 {
 	    # gcc 2.95.3 -gdwarf-2
 	    # gcc 3.3.2 -gdwarf-2
 	    pass "ptype obj_with_enum.priv_enum"
 	}
-	-re "type = enum \{ ?red, green, blue, yellow = 42 ?\}$nl$gdb_prompt $" {
+	-re $re3 {
 	    # This case case is a little dubious, but it's not clear what
 	    # ought to be required of a ptype on a private enum...
 	    # -sts 19990324
diff --git a/gdb/testsuite/gdb.cp/empty-enum.exp b/gdb/testsuite/gdb.cp/empty-enum.exp
index 487d5619e44..0781e486706 100644
--- a/gdb/testsuite/gdb.cp/empty-enum.exp
+++ b/gdb/testsuite/gdb.cp/empty-enum.exp
@@ -53,11 +53,19 @@ gdb_test "print arg2" " = 4"
 # Xfail for missing DW_AT_type in DW_TAG_enumeration_type, gcc PR debug/16063.
 set have_xfail [expr {[test_compiler_info gcc-*] && [gcc_major_version] < 5}]
 
+set enum1 [multi_line "" \
+    "type = enum enum1 : unsigned int {" \
+    "    <no enum values>" \
+    "}"]
+set enum1_no_type [multi_line "" \
+    "type = enum enum1 {" \
+    "    <no enum values>" \
+    "}"]
 gdb_test_multiple "ptype arg1" "" {
-    -re -wrap "type = enum enum1 : unsigned int \\{\\}" {
+    -re -wrap $enum1 {
 	pass $gdb_test_name
     }
-    -re -wrap "type = enum enum1 \\{\\}" {
+    -re -wrap $enum1_no_type {
 	if { $have_xfail } {
 	    setup_xfail *-*-* gcc/16063
 	}
@@ -65,11 +73,19 @@ gdb_test_multiple "ptype arg1" "" {
     }
 }
 
+set enum2 [multi_line "" \
+    "type = enum class enum2 : unsigned char {" \
+    "    <no enum values>" \
+    "}"]
+set enum2_no_type [multi_line "" \
+    "type = enum class enum2 {" \
+    "    <no enum values>" \
+    "}"]
 gdb_test_multiple "ptype arg2" "" {
-    -re -wrap "type = enum class enum2 : unsigned char \\{\\}" {
+    -re -wrap $enum2 {
 	pass $gdb_test_name
     }
-    -re -wrap "type = enum class enum2 \\{\\}" {
+    -re -wrap $enum2_no_type {
 	if { $have_xfail } {
 	    setup_xfail *-*-* gcc/16063
 	}
diff --git a/gdb/testsuite/gdb.cp/enum-class.exp b/gdb/testsuite/gdb.cp/enum-class.exp
index dead0c51511..fbfda8937f0 100644
--- a/gdb/testsuite/gdb.cp/enum-class.exp
+++ b/gdb/testsuite/gdb.cp/enum-class.exp
@@ -29,7 +29,11 @@ if {![runto_main]} {
 }
 
 gdb_test "ptype E1" \
-    "type = enum class E1 (: int )?{E1::HI = 7, E1::THERE}"
+    [multi_line \
+	"type = enum class E1 (: int )?{" \
+	"    E1::HI = 7," \
+	"    E1::THERE = 8" \
+	"}"]
 
 gdb_test "print E1::HI" " = E1::HI"
 gdb_test "print (int) E1::HI" " = 7"
diff --git a/gdb/testsuite/gdb.cp/nested-types.exp b/gdb/testsuite/gdb.cp/nested-types.exp
index 28ce8e0c094..0a4939e5062 100644
--- a/gdb/testsuite/gdb.cp/nested-types.exp
+++ b/gdb/testsuite/gdb.cp/nested-types.exp
@@ -154,9 +154,9 @@ proc make_enum {result_var id parent_list indent_lvl log} {
     upvar $result_var result
 
     set s "[qual_name E$id $parent_list]"
-    set a "[qual_name A$id $parent_list]"
-    set b "[qual_name B$id $parent_list]"
-    set c "[qual_name C$id $parent_list]"
+    set a "[qual_name A$id $parent_list] = 0"
+    set b "[qual_name B$id $parent_list] = 1"
+    set c "[qual_name C$id $parent_list] = 2"
     lappend result [list "type" "public" "enum" $s [list $a $b $c]]
 
     if {$log} {
diff --git a/gdb/testsuite/gdb.dwarf2/enum-type.exp b/gdb/testsuite/gdb.dwarf2/enum-type.exp
index f077c0acb2a..6f751406f9b 100644
--- a/gdb/testsuite/gdb.dwarf2/enum-type.exp
+++ b/gdb/testsuite/gdb.dwarf2/enum-type.exp
@@ -109,11 +109,17 @@ if { [prepare_for_testing "failed to prepare" ${testfile} \
 
 gdb_test "print sizeof(enum E)" " = 4"
 
-gdb_test "ptype enum EU" "type = enum EU {TWO = 2}" \
-    "ptype EU in enum C"
+gdb_test "ptype enum EU" \
+    [multi_line \
+	"type = enum EU {" \
+	"    TWO = 2" \
+	"}"] "ptype EU in enum C"
 gdb_test_no_output "set lang c++"
-gdb_test "ptype enum EU" "type = enum EU : unsigned int {TWO = 2}" \
-    "ptype EU in C++"
+gdb_test "ptype enum EU" \
+    [multi_line \
+	"type = enum EU : unsigned int {" \
+	"    TWO = 2" \
+	"}"] "ptype EU in C++"
 
 gdb_test "p ns::val1" \
     " = ns::val1"
diff --git a/gdb/testsuite/gdb.xml/tdesc-regs.exp b/gdb/testsuite/gdb.xml/tdesc-regs.exp
index 63f5ebc90d8..2dcff9ab468 100644
--- a/gdb/testsuite/gdb.xml/tdesc-regs.exp
+++ b/gdb/testsuite/gdb.xml/tdesc-regs.exp
@@ -212,7 +212,12 @@ gdb_test "ptype \$mixed_flags" \
 	"    bool C @4;" \
 	"    uint32_t D @5;" \
 	"    uint32_t @6-7;" \
-	"    enum Z_values {yes = 1, no = 0, maybe = 2, so} Z @8-9;" \
+	"    enum Z_values {" \
+	"        yes = 1," \
+	"        no = 0," \
+	"        maybe = 2," \
+	"        so = 3" \
+	"    } Z @8-9;" \
 	"}"]
 # Reggroups should have at least general and the extra foo group
 gdb_test "maintenance print reggroups" \
diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp
index ded4cf8aeb6..5795836ce04 100644
--- a/gdb/testsuite/lib/cp-support.exp
+++ b/gdb/testsuite/lib/cp-support.exp
@@ -582,23 +582,44 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table
 
 	    switch $nested_key {
 		enum {
-		    set expected_result \
-			"enum $nested_name (: (unsigned )?int )?\{"
-		    foreach c $nested_children {
-			append expected_result "$c, "
-		    }
-		    set expected_result \
-			[string trimright $expected_result { ,}]
-		    append expected_result "\};"
+		    set expected_result "enum $nested_name : unsigned int \{"
 		    cp_ptype_class_verbose \
 			"Expecting enum result: $expected_result"
-		    if {![regexp -- $expected_result $actual_line]} {
+		    if {![string equal $expected_result $actual_line]} {
 			set txt "$in_testname // wrong nested type enum"
 			append txt " definition: $actual_line"
 			fail $txt
 			queue delete $line_queue
 			return false
 		    }
+		    # This will be followed by lines for each value of the
+		    # enum.
+		    cp_ptype_class_verbose "matched enum value"
+		    foreach m $nested_children {
+			set actual_line \
+			    [cp_support_internal::next_line $line_queue]
+			cp_ptype_class_verbose "Expecting enum value: $m"
+			# Remove the trailing comma from the actual line to
+			# simplify comparison.
+			set trimmed_actual_line \
+			    [string trimright $actual_line " ,"]
+			if {![string equal $m $trimmed_actual_line]} {
+			    set txt "$in_testname // unexpected enum value: "
+			    append txt $m
+			    fail $txt
+			    queue delete $line_queue
+			    return false
+			}
+			cp_ptype_class_verbose "matched enum value \"$m\""
+		    }
+
+		    # Nested enum values always end with a trailing curly brace.
+		    set actual_line [cp_support_internal::next_line $line_queue]
+		    if {![string equal $actual_line "\};"]} {
+			fail "$in_testname // missing closing curly brace"
+			queue delete $line_queue
+			return false
+		    }
 		    cp_ptype_class_verbose "passed enum $nested_name"
 		}
 
-- 
2.43.0

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

* Re: [PATCH 2/3] gdb: Replace \r\n with multi_line to make tests more readable
  2025-11-26 12:03 ` [PATCH 2/3] gdb: Replace \r\n with multi_line to make tests more readable Daniel Knezevic
@ 2025-11-26 12:43   ` Andreas Schwab
  0 siblings, 0 replies; 6+ messages in thread
From: Andreas Schwab @ 2025-11-26 12:43 UTC (permalink / raw)
  To: Daniel Knezevic; +Cc: gdb-patches, Tom Tromey, Pedro Alves, Simon Marchi

On Nov 26 2025, Daniel Knezevic wrote:

>  gdb_test "ptype the_highest" \
> -	 "type = struct highest \{.*\[\r\n\] *int a;.*\[\r\n\] *struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{\.\.\.\} anonymous_level_2;.*\[\r\n\] *\} anonymous_level_1;.*\[\r\n\]}.*" \
> -	 "ptype the_highest"
> +    [multi_line \
> +	"type = struct highest {" \
> +	"    int a;" \
> +	"    struct {" \
> +	"        int b;" \
> +	"        struct \{\.\.\.\} anonymous_level_2;" \
> +	"    \} anonymous_level_1;" \

The single backslashes inside double quotes are eaten by the tcl string
parser and won't survive into the resulting regexp.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH 0/3 v4] gdb: Make printing enum types prettier
  2025-11-26 12:02 [PATCH 0/3 v4] gdb: Make printing enum types prettier Daniel Knezevic
                   ` (2 preceding siblings ...)
  2025-11-26 12:03 ` [PATCH 3/3] gdb: Make printing enum types prettier Daniel Knezevic
@ 2025-12-01 20:23 ` Tom Tromey
  3 siblings, 0 replies; 6+ messages in thread
From: Tom Tromey @ 2025-12-01 20:23 UTC (permalink / raw)
  To: Daniel Knezevic; +Cc: gdb-patches, Tom Tromey, Pedro Alves, Simon Marchi

>>>>> "Daniel" == Daniel Knezevic <daniel.knezevic@htecgroup.com> writes:

Daniel> This is v4 of:
Daniel>   https://inbox.sourceware.org/gdb-patches/20251124132726.325366-1-daniel.knezevic@htecgroup.com/

Thanks for doing this.  Do you have a copyright assignment on file?  If
not I think we will need one before we can check in this series -- send
me email and I can get you started.

Tom

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

end of thread, other threads:[~2025-12-01 20:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-26 12:02 [PATCH 0/3 v4] gdb: Make printing enum types prettier Daniel Knezevic
2025-11-26 12:02 ` [PATCH 1/3] gdb: Move logic for printing enums to a helper function Daniel Knezevic
2025-11-26 12:03 ` [PATCH 2/3] gdb: Replace \r\n with multi_line to make tests more readable Daniel Knezevic
2025-11-26 12:43   ` Andreas Schwab
2025-11-26 12:03 ` [PATCH 3/3] gdb: Make printing enum types prettier Daniel Knezevic
2025-12-01 20:23 ` [PATCH 0/3 v4] " Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox