diff --git a/gdb/NEWS b/gdb/NEWS
index dee0ac2ecd8..62b15094dee 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -114,6 +114,15 @@ maintenance info line-table
   entry corresponds to an address where a breakpoint should be placed
   to be at the first instruction past a function's prologue.
 
+* MI changes
+
+  ** The '-stack-list-arguments', '-stack-list-locals',
+     '-stack-list-variables', and '-var-list-children' commands
+     support the '--scalar-values' option, which requests the command
+     to print values only for scalar types.  Support for this feature
+     can be verified by using the '-list-features' command, which
+     should contain "scalar-values".
+
 * New targets
 
 GNU/Linux/LoongArch (gdbserver)	loongarch*-*-linux*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 238a49b027d..b2b53de1022 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33326,12 +33326,14 @@ larger than the actual number of frames.  On the other hand,
 @var{high-frame} may be larger than the actual number of frames, in
 which case only existing frames will be returned.
 
-If @var{print-values} is 0 or @code{--no-values}, print only the names of
-the variables; if it is 1 or @code{--all-values}, print also their
-values; and if it is 2 or @code{--simple-values}, print the name,
-type and value for simple data types, and the name and type for arrays,
-structures and unions.  If the option @code{--no-frame-filters} is
-supplied, then Python frame filters will not be executed.
+If @var{print-values} is 0 or @code{--no-values}, print only the names
+of the variables; if it is 1 or @code{--all-values}, print also their
+values; if it is 2 or @code{--simple-values}, print the name, type and
+value for simple data types, and the name and type for arrays,
+structures and unions; and if it is 3 or @code{--scalar-values}, print
+the name, type and value for scalar data types, and the name and type
+otherwise.  If the option @code{--no-frame-filters} is supplied, then
+Python frame filters will not be executed.
 
 If the @code{--skip-unavailable} option is specified, arguments that
 are not available are not listed.  Partially available arguments
@@ -33549,13 +33551,15 @@ Show a single frame:
 Display the local variable names for the selected frame.  If
 @var{print-values} is 0 or @code{--no-values}, print only the names of
 the variables; if it is 1 or @code{--all-values}, print also their
-values; and if it is 2 or @code{--simple-values}, print the name,
-type and value for simple data types, and the name and type for arrays,
-structures and unions.  In this last case, a frontend can immediately
-display the value of simple data types and create variable objects for
-other data types when the user wishes to explore their values in
-more detail.  If the option @code{--no-frame-filters} is supplied, then
-Python frame filters will not be executed.
+values; if it is 2 or @code{--simple-values}, print the name, type and
+value for simple data types, and the name and type for arrays,
+structures and unions; and if it is 3 or @code{--scalar-values}, print
+the name, type and value for scalar data types, and the name and type
+otherwise.  In the last two cases, a frontend can immediately display
+the value of simple or scalar data types and create variable objects
+for other data types when the user wishes to explore their values in
+more detail.  If the option @code{--no-frame-filters} is supplied,
+then Python frame filters will not be executed.
 
 If the @code{--skip-unavailable} option is specified, local variables
 that are not available are not listed.  Partially available local
@@ -33594,13 +33598,16 @@ This command is deprecated in favor of the
  -stack-list-variables [ --no-frame-filters ] [ --skip-unavailable ] @var{print-values}
 @end smallexample
 
-Display the names of local variables and function arguments for the selected frame.  If
-@var{print-values} is 0 or @code{--no-values}, print only the names of
-the variables; if it is 1 or @code{--all-values}, print also their
-values; and if it is 2 or @code{--simple-values}, print the name,
-type and value for simple data types, and the name and type for arrays,
-structures and unions.  If the option @code{--no-frame-filters} is
-supplied, then Python frame filters will not be executed.
+Display the names of local variables and function arguments for the
+selected frame.  If @var{print-values} is 0 or @code{--no-values},
+print only the names of the variables; if it is 1 or
+@code{--all-values}, print also their values; if it is 2 or
+@code{--simple-values}, print the name, type and value for simple data
+types, and the name and type for arrays, structures and unions; and if
+it is 3 or @code{--scalar-values}, print the name, type and value for
+scalar data types, and the name and type otherwise.  If the option
+@code{--no-frame-filters} is supplied, then Python frame filters will
+not be executed.
 
 If the @code{--skip-unavailable} option is specified, local variables
 and arguments that are not available are not listed.  Partially
@@ -34029,9 +34036,10 @@ create variable objects for them, if they do not already exist.  With
 a single argument or if @var{print-values} has a value of 0 or
 @code{--no-values}, print only the names of the variables; if
 @var{print-values} is 1 or @code{--all-values}, also print their
-values; and if it is 2 or @code{--simple-values} print the name and
-value for simple data types and just the name for arrays, structures
-and unions.
+values; if it is 2 or @code{--simple-values} print the name and value
+for simple data types and just the name for arrays, structures and
+unions; and if it is 3 or @code{--scalar-values}, print the name and
+value for scalar data types, and just the name otherwise.
 
 @var{from} and @var{to}, if specified, indicate the range of children
 to report.  If @var{from} or @var{to} is less than zero, the range is
@@ -37295,6 +37303,11 @@ option (@pxref{GDB/MI Program Execution}).
 @item data-disassemble-a-option
 Indicates that the @code{-data-disassemble} command supports the @option{-a}
 option (@pxref{GDB/MI Data Manipulation}).
+@item scalar-values
+Indicates that the @code{-stack-list-arguments},
+@code{-stack-list-locals}, @code{-stack-list-variables}, and
+@code{-var-list-children} commands support the
+@option{--scalar-values} option (@pxref{GDB/MI Stack Manipulation}).
 @end ftable
 
 @subheading The @code{-list-target-features} Command
diff --git a/gdb/extension.h b/gdb/extension.h
index 47839ea50be..16d12f00f41 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -121,6 +121,9 @@ enum ext_lang_frame_args
        arguments when invoked from the MI. */
     MI_PRINT_SIMPLE_VALUES = PRINT_SIMPLE_VALUES,
 
+    /* Print only scalar values for arguments when invoked from the MI.  */
+    MI_PRINT_SCALAR_VALUES = PRINT_SCALAR_VALUES,
+
     /* Print only scalar values for arguments when invoked from the CLI. */
     CLI_SCALAR_VALUES,
 
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index 0fe204dbc66..d3ae350f166 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -494,6 +494,7 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
   gdb_assert ((values == PRINT_NO_VALUES && arg->val == NULL
 	       && arg->error == NULL)
 	      || values == PRINT_SIMPLE_VALUES
+	      || values == PRINT_SCALAR_VALUES
 	      || (values == PRINT_ALL_VALUES
 		  && (arg->val != NULL || arg->error != NULL)));
   gdb_assert (arg->entry_kind == print_entry_values_no
@@ -525,7 +526,8 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
   if (what == all && arg->sym->is_argument ())
     uiout->field_signed ("arg", 1);
 
-  if (values == PRINT_SIMPLE_VALUES)
+  if (values == PRINT_SIMPLE_VALUES
+      || values == PRINT_SCALAR_VALUES)
     {
       check_typedef (arg->sym->type ());
       type_print (arg->sym->type (), "", &stb, -1);
@@ -557,6 +559,25 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
     }
 }
 
+/* Print SYM according to VALUES?  */
+
+static bool
+print_symbol_p (struct symbol *sym, enum print_values values)
+{
+  switch (values)
+    {
+    default:
+    case PRINT_NO_VALUES:
+      return false;
+    case PRINT_ALL_VALUES:
+      return true;
+    case PRINT_SIMPLE_VALUES:
+      return mi_simple_values_type_p (sym->type ());
+    case PRINT_SCALAR_VALUES:
+      return val_print_scalar_type_p (sym->type ());
+    }
+}
+
 /* Print a list of the objects for the frame FI in a certain form,
    which is determined by VALUES.  The objects can be locals,
    arguments or both, which is determined by WHAT.  If SKIP_UNAVAILABLE
@@ -571,7 +592,6 @@ list_args_or_locals (const frame_print_options &fp_opts,
   const struct block *block;
   struct symbol *sym;
   struct block_iterator iter;
-  struct type *type;
   const char *name_of_result;
   struct ui_out *uiout = current_uiout;
 
@@ -647,21 +667,12 @@ list_args_or_locals (const frame_print_options &fp_opts,
 	      entryarg.sym = sym2;
 	      entryarg.entry_kind = print_entry_values_no;
 
-	      switch (values)
+	      if (print_symbol_p (sym, values))
 		{
-		case PRINT_SIMPLE_VALUES:
-		  type = check_typedef (sym2->type ());
-		  if (type->code () != TYPE_CODE_ARRAY
-		      && type->code () != TYPE_CODE_STRUCT
-		      && type->code () != TYPE_CODE_UNION)
-		    {
-		case PRINT_ALL_VALUES:
 		  if (sym->is_argument ())
 		    read_frame_arg (fp_opts, sym2, fi, &arg, &entryarg);
 		  else
 		    read_frame_local (sym2, fi, &arg);
-		    }
-		  break;
 		}
 
 	      if (arg.entry_kind != print_entry_values_only)
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 3db09cf7815..064d13a3729 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -32,6 +32,7 @@
 #include "mi-parse.h"
 #include "gdbsupport/gdb_optional.h"
 #include "inferior.h"
+#include "valprint.h"
 
 static void varobj_update_one (struct varobj *var,
 			       enum print_values print_values,
@@ -334,15 +335,26 @@ mi_print_value_p (struct varobj *var, enum print_values print_values)
   type = varobj_get_gdb_type (var);
   if (type == NULL)
     return 1;
+  else if (print_values == PRINT_SCALAR_VALUES)
+    return val_print_scalar_type_p (type);
   else
-    {
-      type = check_typedef (type);
+    return mi_simple_values_type_p (type);
+}
+
+/* See mi-cmds.h.  */
 
-      /* For PRINT_SIMPLE_VALUES, only print the value if it has a type
-	 and that type is not a compound type.  */
-      return (type->code () != TYPE_CODE_ARRAY
-	      && type->code () != TYPE_CODE_STRUCT
-	      && type->code () != TYPE_CODE_UNION);
+bool
+mi_simple_values_type_p (struct type *type)
+{
+  type = check_typedef (type);
+  switch (type->code ())
+    {
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      return false;
+    default:
+      return true;
     }
 }
 
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 9ffb11bf997..56c3ccb8b8a 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -29,7 +29,8 @@
 enum print_values {
    PRINT_NO_VALUES,
    PRINT_ALL_VALUES,
-   PRINT_SIMPLE_VALUES
+   PRINT_SIMPLE_VALUES,
+   PRINT_SCALAR_VALUES
 };
 
 typedef void (mi_cmd_argv_ftype) (const char *command, char **argv, int argc);
@@ -226,4 +227,9 @@ using remove_mi_cmd_entries_ftype
   = gdb::function_view<bool (mi_command *)>;
 extern void remove_mi_cmd_entries (remove_mi_cmd_entries_ftype callback);
 
+/* Return true if type is suitable for printing with PRINT_SIMPLE_VALUES: that
+   is, if type is not an array, structure or union.  */
+
+extern bool mi_simple_values_type_p (struct type *type);
+
 #endif /* MI_MI_CMDS_H */
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index b758f398e2a..2e70bcde2da 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -1663,6 +1663,7 @@ mi_cmd_list_features (const char *command, char **argv, int argc)
       uiout->field_string (NULL, "undefined-command-error-code");
       uiout->field_string (NULL, "exec-run-start-option");
       uiout->field_string (NULL, "data-disassemble-a-option");
+      uiout->field_string (NULL, "scalar-values");
 
       if (ext_lang_initialized_p (get_ext_lang_defn (EXT_LANG_PYTHON)))
 	uiout->field_string (NULL, "python");
@@ -2456,20 +2457,39 @@ mi_cmd_ada_task_info (const char *command, char **argv, int argc)
   print_ada_task_info (current_uiout, argv[0], current_inferior ());
 }
 
+/* Print VAL according to VALUES?  */
+
+static bool
+print_value_p (struct value *val, enum print_values values)
+{
+  switch (values)
+    {
+    default:
+    case PRINT_NO_VALUES:
+      return false;
+    case PRINT_ALL_VALUES:
+      return true;
+    case PRINT_SIMPLE_VALUES:
+      return mi_simple_values_type_p (value_type (val));
+    case PRINT_SCALAR_VALUES:
+      return val_print_scalar_type_p (value_type (val));
+    }
+}
+
 /* Print EXPRESSION according to VALUES.  */
 
 static void
 print_variable_or_computed (const char *expression, enum print_values values)
 {
   struct value *val;
-  struct type *type;
   struct ui_out *uiout = current_uiout;
 
   string_file stb;
 
   expression_up expr = parse_expression (expression);
 
-  if (values == PRINT_SIMPLE_VALUES)
+  if (values == PRINT_SIMPLE_VALUES
+      || values == PRINT_SCALAR_VALUES)
     val = evaluate_type (expr.get ());
   else
     val = evaluate_expression (expr.get ());
@@ -2482,31 +2502,19 @@ print_variable_or_computed (const char *expression, enum print_values values)
   switch (values)
     {
     case PRINT_SIMPLE_VALUES:
-      type = check_typedef (value_type (val));
+    case PRINT_SCALAR_VALUES:
       type_print (value_type (val), "", &stb, -1);
       uiout->field_stream ("type", stb);
-      if (type->code () != TYPE_CODE_ARRAY
-	  && type->code () != TYPE_CODE_STRUCT
-	  && type->code () != TYPE_CODE_UNION)
-	{
-	  struct value_print_options opts;
-
-	  get_no_prettyformat_print_options (&opts);
-	  opts.deref_ref = 1;
-	  common_val_print (val, &stb, 0, &opts, current_language);
-	  uiout->field_stream ("value", stb);
-	}
       break;
-    case PRINT_ALL_VALUES:
-      {
-	struct value_print_options opts;
+    }
 
-	get_no_prettyformat_print_options (&opts);
-	opts.deref_ref = 1;
-	common_val_print (val, &stb, 0, &opts, current_language);
-	uiout->field_stream ("value", stb);
-      }
-      break;
+  if (print_value_p (val, values))
+    {
+      struct value_print_options opts;
+      get_no_prettyformat_print_options (&opts);
+      opts.deref_ref = 1;
+      common_val_print (val, &stb, 0, &opts, current_language);
+      uiout->field_stream ("value", stb);
     }
 }
 
diff --git a/gdb/mi/mi-parse.c b/gdb/mi/mi-parse.c
index dfa7b462714..dd70e4648a1 100644
--- a/gdb/mi/mi-parse.c
+++ b/gdb/mi/mi-parse.c
@@ -29,6 +29,7 @@
 #include "language.h"
 
 static const char mi_no_values[] = "--no-values";
+static const char mi_scalar_values[] = "--scalar-values";
 static const char mi_simple_values[] = "--simple-values";
 static const char mi_all_values[] = "--all-values";
 
@@ -383,8 +384,11 @@ mi_parse_print_values (const char *name)
    else if (strcmp (name, "2") == 0
 	    || strcmp (name, mi_simple_values) == 0)
      return PRINT_SIMPLE_VALUES;
+   else if (strcmp (name, "3") == 0
+	    || strcmp (name, mi_scalar_values) == 0)
+     return PRINT_SCALAR_VALUES;
    else
      error (_("Unknown value for PRINT_VALUES: must be: \
-0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
-	    mi_no_values, mi_all_values, mi_simple_values);
+0 or \"%s\", 1 or \"%s\", 2 or \"%s\", 3 or \"%s\""),
+	    mi_no_values, mi_all_values, mi_simple_values, mi_scalar_values);
 }
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index 366f3745b9d..a746f309187 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -232,17 +232,17 @@ py_print_value (struct ui_out *out, struct value *val,
   /* MI does not print certain values, differentiated by type,
      depending on what ARGS_TYPE indicates.  Test type against option.
      For CLI print all values.  */
-  if (args_type == MI_PRINT_SIMPLE_VALUES
+  if (args_type == MI_PRINT_SCALAR_VALUES
+      || args_type == MI_PRINT_SIMPLE_VALUES
       || args_type == MI_PRINT_ALL_VALUES)
     {
-      struct type *type = check_typedef (value_type (val));
-
       if (args_type == MI_PRINT_ALL_VALUES)
 	should_print = 1;
+      else if (args_type == MI_PRINT_SCALAR_VALUES
+	       && val_print_scalar_type_p (value_type (val)))
+	should_print = 1;
       else if (args_type == MI_PRINT_SIMPLE_VALUES
-	       && type->code () != TYPE_CODE_ARRAY
-	       && type->code () != TYPE_CODE_STRUCT
-	       && type->code () != TYPE_CODE_UNION)
+	       && mi_simple_values_type_p (value_type (val)))
 	should_print = 1;
     }
   else if (args_type != NO_VALUES)
@@ -371,10 +371,12 @@ py_print_single_arg (struct ui_out *out,
   if (print_args_field)
     out->field_signed ("arg", 1);
 
-  /* For MI print the type, but only for simple values.  This seems
-     weird, but this is how MI choose to format the various output
+  /* For MI print the type, but only for scalar and simple values. This
+     seems weird, but this is how MI chooses to format the various output
      types.  */
-  if (args_type == MI_PRINT_SIMPLE_VALUES && val != NULL)
+  if ((args_type == MI_PRINT_SCALAR_VALUES
+       || args_type == MI_PRINT_SIMPLE_VALUES)
+      && val != NULL)
     py_print_type (out, val);
 
   if (val != NULL)
@@ -603,7 +605,8 @@ enumerate_locals (PyObject *iter,
       out->field_string ("name", sym_name.get ());
       out->text (" = ");
 
-      if (args_type == MI_PRINT_SIMPLE_VALUES)
+      if (args_type == MI_PRINT_SCALAR_VALUES
+          || args_type == MI_PRINT_SIMPLE_VALUES)
 	py_print_type (out, val);
 
       /* CLI always prints values for locals.  MI uses the
diff --git a/gdb/testsuite/gdb.mi/mi-stack.exp b/gdb/testsuite/gdb.mi/mi-stack.exp
index d04c8153c65..8aa4e2234ff 100644
--- a/gdb/testsuite/gdb.mi/mi-stack.exp
+++ b/gdb/testsuite/gdb.mi/mi-stack.exp
@@ -93,6 +93,9 @@ proc test_stack_args_listing {} {
     # -stack-list-arguments 1 1 1
     # -stack-list-arguments 1 1 3
     # -stack-list-arguments 
+    # -stack-list-arguments 1 1 300
+    # -stack-list-arguments 2 1 1
+    # -stack-list-arguments 3 1 1
 
     mi_gdb_test "231-stack-list-arguments 0" \
 	"231\\^done,stack-args=\\\[frame=\{level=\"0\",args=\\\[\\\]\},frame=\{level=\"1\",args=\\\[name=\"strarg\"\\\]\},frame=\{level=\"2\",args=\\\[name=\"intarg\",name=\"strarg\"\\\]\},frame=\{level=\"3\",args=\\\[name=\"intarg\",name=\"strarg\",name=\"fltarg\"\\\]\},frame=\{level=\"4\",args=\\\[\\\]\}\\\]" \
@@ -125,6 +128,14 @@ proc test_stack_args_listing {} {
     mi_gdb_test "235-stack-list-arguments 1 1 300" \
 	"235\\^done,stack-args=\\\[frame=\{level=\"1\",args=\\\[\{name=\"strarg\",value=\"$hex \\\\\"A string argument.\\\\\"\"\}\\\]\},frame=\{level=\"2\",args=\\\[\{name=\"intarg\",value=\"2\"\},\{name=\"strarg\",value=\"$hex \\\\\"A string argument.\\\\\"\"\}\\\]\},frame=\{level=\"3\",args=\\\[\{name=\"intarg\",value=\"2\"\},\{name=\"strarg\",value=\"$hex \\\\\"A string argument.\\\\\"\"\},\{name=\"fltarg\",value=\"3.5\"\}\\\]\},frame=\{level=\"4\",args=\\\[\\\]\}\\\]" \
 	"stack args listing 1 1 300"
+
+    mi_gdb_test "236-stack-list-arguments 2 1 1" \
+	"236\\^done,stack-args=\\\[frame=\{level=\"1\",args=\\\[\{name=\"strarg\",type=\"char \\*\",value=\"$hex \\\\\"A string argument.\\\\\"\"\}\\\]\}\\\]" \
+	"stack args listing --simple-values 1 1"
+
+    mi_gdb_test "237-stack-list-arguments 3 1 1" \
+	"237\\^done,stack-args=\\\[frame=\{level=\"1\",args=\\\[\{name=\"strarg\",type=\"char \\*\",value=\"$hex \\\\\"A string argument.\\\\\"\"\}\\\]\}\\\]" \
+	"stack args listing --scalar-values 1 1"
 }
 
 proc test_stack_info_depth {} {
@@ -163,7 +174,7 @@ proc test_stack_locals_listing {} {
     # -stack-list-locals 0 (--no-values)
     # -stack-list-locals 1 (--all-values)
     # -stack-list-locals 2 (--simple-values)
-    # -stack-list-arguments 
+    # -stack-list-locals 3 (--scalar-values)
 
     mi_gdb_test "232-stack-list-locals 0" \
 	"232\\^done,locals=\\\[name=\"A\",name=\"B\",name=\"C\",name=\"D\"\\\]" \
@@ -183,6 +194,10 @@ proc test_stack_locals_listing {} {
 	"232\\^done,locals=\\\[\{name=\"A\",type=\"int\",value=\"1\"\},\{name=\"B\",type=\"int\",value=\"2\"\},\{name=\"C\",type=\"int\",value=\"3\"\},\{name=\"D\",type=\"int \\\[3\\\]\"\}\\\]" \
 	"stack locals listing, simple types: names and values, complex type: names and types"
 
+    mi_gdb_test "233-stack-list-locals --scalar-values" \
+	"233\\^done,locals=\\\[\{name=\"A\",type=\"int\",value=\"1\"\},\{name=\"B\",type=\"int\",value=\"2\"\},\{name=\"C\",type=\"int\",value=\"3\"\},\{name=\"D\",type=\"int \\\[3\\\]\"\}\\\]" \
+	"stack locals listing, scalar types: names and values, otherwise: names and types"
+
     mi_gdb_test "234-stack-list-locals" \
 	"234\\^error,msg=\"-stack-list-locals: Usage.*PRINT_VALUES.*\"" \
 	"stack locals listing wrong"
diff --git a/gdb/testsuite/gdb.mi/print-scalar-values.cc b/gdb/testsuite/gdb.mi/print-scalar-values.cc
new file mode 100644
index 00000000000..fd9daf1d962
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/print-scalar-values.cc
@@ -0,0 +1,58 @@
+/* This test case is part of GDB, the GNU debugger.
+
+   Copyright 2022 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* PRINT_SCALAR_VALUES test program.
+
+   Test that PRINT_SCALAR_VALUES distinguishes scalar and non-scalar
+   types, including C++ reference and rvalue reference types.
+
+   In the function f(), arguments i, ir, and irr are ints or references
+   to ints, and their values should be printed by PRINT_SCALAR_VALUES;
+   but the other arguments are non-scalar, and so their values should
+   not be printed by PRINT_SCALAR_VALUES.  */
+
+struct s
+{
+  int v;
+};
+
+union u
+{
+  int v;
+};
+
+int
+f (int i, int &ir, int &&irr,
+   int a[1], int (&ar)[1], int (&&arr)[1],
+   struct s s, struct s &sr, struct s &&srr,
+   union u u, union u &ur, union u &&urr)
+{
+  return (i + ir + irr
+          + a[0] + ar[0] + arr[0]
+          + s.v + sr.v + srr.v
+          + u.v + ur.v + urr.v);
+}
+
+int
+main (void)
+{
+  int i = 1, j = 2;
+  int a[1] = { 4 }, b[1] = { 5 };
+  struct s s = { 7 }, t = { 8 };
+  union u u = { 10 }, v = { 11 };
+  return f (i, j, 3, a, b, { 6 }, s, t, { 9 }, u, v, { 12 });
+}
diff --git a/gdb/testsuite/gdb.mi/print-scalar-values.exp b/gdb/testsuite/gdb.mi/print-scalar-values.exp
new file mode 100644
index 00000000000..3398218c063
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/print-scalar-values.exp
@@ -0,0 +1,51 @@
+# Copyright 2022 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# PRINT_SCALAR_VALUES test.
+#
+# Test that PRINT_SCALAR_VALUES distinguishes scalar and non-scalar
+# types, including C++ reference and rvalue reference types.
+#
+# In the function f(), arguments i, ir, and irr are ints or references
+# to ints, and their values should be printed by PRINT_SCALAR_VALUES;
+# but the other arguments are non-scalar, and so their values should not
+# be printed by PRINT_SCALAR_VALUES.
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib mi-support.exp
+standard_testfile .cc
+
+if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable {debug c++}] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+mi_clean_restart $binfile
+
+mi_runto_main
+
+mi_gdb_test "-break-insert f" "\\^done.*" "set breakpoint on f"
+
+mi_send_resuming_command "exec-continue" "exec-continue to breakpoint on f"
+
+mi_expect_stop "breakpoint-hit" "f" ".*" ".*" ".*" {.* disp="keep"} \
+    "run until breakpoint on f"
+
+mi_gdb_test "-stack-list-arguments --scalar-values" \
+    "\\^done,stack-args=\\\[frame=\{level=\"0\",args=\\\[\{name=\"i\",type=\"int\",value=\"1\"\},\{name=\"ir\",type=\"int &\",value=\"@$hex: 2\"\},\{name=\"irr\",type=\"int &&\",value=\"@$hex: 3\"\},\{name=\"a\",type=\"int \\*\",value=\"$hex\"\},\{name=\"ar\",type=\"int \\(&\\)\\\[1\\\]\"\},\{name=\"arr\",type=\"int \\(&&\\)\\\[1\\\]\"\},\{name=\"s\",type=\"s\"\},\{name=\"sr\",type=\"s &\"\},\{name=\"srr\",type=\"s &&\"\},\{name=\"u\",type=\"u\"\},\{name=\"ur\",type=\"u &\"\},\{name=\"urr\",type=\"u &&\"\}\\\]\},frame=\{level=\"1\",args=\\\[\\\]\}\\\]" \
+    "stack list arguments, scalar types: names, types and values, compound types: names and types"
+
+mi_gdb_exit
