]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Make "p S::method() const::static_var" work too
authorPedro Alves <palves@redhat.com>
Mon, 4 Sep 2017 19:21:16 +0000 (20:21 +0100)
committerPedro Alves <palves@redhat.com>
Mon, 4 Sep 2017 19:21:16 +0000 (20:21 +0100)
Trying to print a function local static variable of a const-qualified
method still doesn't work after the previous fixes:

  (gdb) p 'S::method() const'::static_var
  $1 = {i1 = 1, i2 = 2, i3 = 3}
  (gdb) p S::method() const::static_var
  No symbol "static_var" in specified context.

The reason is that the expression parser/evaluator loses the "const",
and the above unquoted case is just like trying to print a variable of
the non-const overload, if it exists, even.  As if the above unquoted
case had been written as:

  (gdb) p S::method()::static_var
  No symbol "static_var" in specified context.

We can see the problem without static vars in the picture.  With:

 struct S
 {
    void method ();
    void method () const;
 };

Compare:

  (gdb) print 'S::method(void) const'
  $1 = {void (const S * const)} 0x400606 <S::method() const>
  (gdb) print S::method(void) const
  $2 = {void (S * const)} 0x4005d8 <S::method()>   # wrong method!

That's what we need to fix.  If we fix that, the function local static
case starts working.

The grammar production for function/method types is this one:

  exp:       exp '(' parameter_typelist ')' const_or_volatile

This results in a TYPE_INSTANCE expression evaluator operator.  For
the example above, we get something like this ("set debug expression 1"):

...
            0  TYPE_INSTANCE         1 TypeInstance: Type @0x560fda958be0 (void)
            5    OP_SCOPE              Type @0x560fdaa544d8 (S) Field name: `method'
...

While evaluating TYPE_INSTANCE, we end up in
value_struct_elt_for_reference, trying to find the method named
"method" that has the prototype recorded in TYPE_INSTANCE.  In this
case, TYPE_INSTANCE says that we're looking for a method that has
"(void)" as parameters (that's what "1 TypeInstance: Type
@0x560fda958be0 (void)" above means.  The trouble is that nowhere in
this mechanism do we communicate to value_struct_elt_for_reference
that we're looking for the _const_ overload.
value_struct_elt_for_reference only compared parameters, and the
non-const "method()" overload has matching parameters, so it's
considered the right match...

Conveniently, the "const_or_volatile" production in the grammar
already records "const" and "volatile" info in the type stack.  The
type stack is not used in this code path, but we can borrow the
information.  The patch converts the info in the type stack to an
"instance flags" enum, and adds that as another element in
TYPE_INSTANCE operators.  This type instance flags is then applied to
the temporary type that is passed to value_struct_elt_for_reference
for matching.

The other side of the problem is that methods in the debug info aren't
marked const/volatile, so with that in place, the matching never finds
const/volatile-qualified methods.

The problem is that in the DWARF, there's no indication at all whether
a method is const/volatile qualified...  For example (c++filt applied
to the linkage name for convenience):

   <2><d3>: Abbrev Number: 6 (DW_TAG_subprogram)
      <d4>   DW_AT_external    : 1
      <d4>   DW_AT_name        : (indirect string, offset: 0x3df): method
      <d8>   DW_AT_decl_file   : 1
      <d9>   DW_AT_decl_line   : 58
      <da>   DW_AT_linkage_name: (indirect string, offset: 0x5b2): S::method() const
      <de>   DW_AT_declaration : 1
      <de>   DW_AT_object_pointer: <0xe6>
      <e2>   DW_AT_sibling     : <0xec>

I see the same with both GCC and Clang.  The patch works around this
by extracting the cv qualification from the "const" and "volatile" in
the demangled name.  This will need further tweaking for "&" and
"const &" overloads, but we don't support them in the parser yet,
anyway.

The TYPE_CONST changes were necessary otherwise the comparisons in valops.c:

  if (TYPE_CONST (intype) != TYPE_FN_FIELD_CONST (f, j))
    continue;

would fail, because when both TYPE_CONST() TYPE_FN_FIELD_CONST() were
true, their values were different.

BTW, I'm recording the const/volatile-ness of methods in the
TYPE_FN_FIELD info because #1 - I'm not sure it's kosher to change the
method's type directly (vs having to call make_cv_type to create a new
type), and #2 it's what stabsread.c does:

...
    case 'A': /* Normal functions.  */
      new_sublist->fn_field.is_const = 0;
      new_sublist->fn_field.is_volatile = 0;
      (*pp)++;
      break;
    case 'B': /* `const' member functions.  */
      new_sublist->fn_field.is_const = 1;
      new_sublist->fn_field.is_volatile = 0;
...

After all this, this finally all works:

  print S::method(void) const
  $1 = {void (const S * const)} 0x400606 <S::method() const>
  (gdb) p S::method() const::static_var
  $2 = {i1 = 1, i2 = 2, i3 = 3}

gdb/ChangeLog:
2017-09-04  Pedro Alves  <palves@redhat.com>

* c-exp.y (function_method, function_method_void): Add current
instance flags to TYPE_INSTANCE.
* dwarf2read.c (check_modifier): New.
(compute_delayed_physnames): Assert that only C++ adds delayed
physnames.  Mark fn_fields as const/volatile depending on
physname.
* eval.c (make_params): New type_instance_flags parameter.  Use
it as the new type's instance flags.
(evaluate_subexp_standard) <TYPE_INSTANCE>: Extract the instance
flags element and pass it to make_params.
* expprint.c (print_subexp_standard) <TYPE_INSTANCE>: Handle
instance flags element.
(dump_subexp_body_standard) <TYPE_INSTANCE>: Likewise.
* gdbtypes.h: Include "enum-flags.h".
(type_instance_flags): New enum-flags type.
(TYPE_CONST, TYPE_VOLATILE, TYPE_RESTRICT, TYPE_ATOMIC)
(TYPE_CODE_SPACE, TYPE_DATA_SPACE): Return boolean.
* parse.c (operator_length_standard) <TYPE_INSTANCE>: Adjust.
(follow_type_instance_flags): New function.
(operator_check_standard) <TYPE_INSTANCE>: Adjust.
* parser-defs.h (follow_type_instance_flags): Declare.
* valops.c (value_struct_elt_for_reference): const/volatile must
match too.

gdb/testsuite/ChangeLog:
2017-09-04  Pedro Alves  <palves@redhat.com>

* gdb.base/func-static.c (S::method const, S::method volatile)
(S::method volatile const): New methods.
(c_s, v_s, cv_s): New instances.
(main): Call method() on them.
* gdb.base/func-static.exp (syntax_re, cannot_resolve_re): New variables.
(cannot_resolve): New procedure.
(cxx_scopes_list): Test cv methods.  Add print-scope-quote and
print-quote-unquoted columns.
(do_test): Test printing each scope too.

12 files changed:
gdb/ChangeLog
gdb/c-exp.y
gdb/dwarf2read.c
gdb/eval.c
gdb/expprint.c
gdb/gdbtypes.h
gdb/parse.c
gdb/parser-defs.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.cp/local-static.c
gdb/testsuite/gdb.cp/local-static.exp
gdb/valops.c

index cdcbfaee932f15f9912850ef17719e50cc499629..196fe60950bc418b7742b31844ac6312ee8c6b8f 100644 (file)
@@ -1,3 +1,29 @@
+2017-09-04  Pedro Alves  <palves@redhat.com>
+
+       * c-exp.y (function_method, function_method_void): Add current
+       instance flags to TYPE_INSTANCE.
+       * dwarf2read.c (check_modifier): New.
+       (compute_delayed_physnames): Assert that only C++ adds delayed
+       physnames.  Mark fn_fields as const/volatile depending on
+       physname.
+       * eval.c (make_params): New type_instance_flags parameter.  Use
+       it as the new type's instance flags.
+       (evaluate_subexp_standard) <TYPE_INSTANCE>: Extract the instance
+       flags element and pass it to make_params.
+       * expprint.c (print_subexp_standard) <TYPE_INSTANCE>: Handle
+       instance flags element.
+       (dump_subexp_body_standard) <TYPE_INSTANCE>: Likewise.
+       * gdbtypes.h: Include "enum-flags.h".
+       (type_instance_flags): New enum-flags type.
+       (TYPE_CONST, TYPE_VOLATILE, TYPE_RESTRICT, TYPE_ATOMIC)
+       (TYPE_CODE_SPACE, TYPE_DATA_SPACE): Return boolean.
+       * parse.c (operator_length_standard) <TYPE_INSTANCE>: Adjust.
+       (follow_type_instance_flags): New function.
+       (operator_check_standard) <TYPE_INSTANCE>: Adjust.
+       * parser-defs.h (follow_type_instance_flags): Declare.
+       * valops.c (value_struct_elt_for_reference): const/volatile must
+       match too.
+
 2017-09-04  Pedro Alves  <palves@redhat.com>
 
        * cp-namespace.c (cp_search_static_and_baseclasses): Handle
index f7f098ba525aea86947db5a7254709a951ac4038..bcc3e12dfc559679188be091055528c58f5db524 100644 (file)
@@ -558,6 +558,11 @@ function_method:       exp '(' parameter_typelist ')' const_or_volatile
                          LONGEST len = VEC_length (type_ptr, type_list);
 
                          write_exp_elt_opcode (pstate, TYPE_INSTANCE);
+                         /* Save the const/volatile qualifiers as
+                            recorded by the const_or_volatile
+                            production's actions.  */
+                         write_exp_elt_longcst (pstate,
+                                                follow_type_instance_flags ());
                          write_exp_elt_longcst (pstate, len);
                          for (i = 0;
                               VEC_iterate (type_ptr, type_list, i, type_elt);
@@ -571,6 +576,9 @@ function_method:       exp '(' parameter_typelist ')' const_or_volatile
 
 function_method_void:      exp '(' ')' const_or_volatile
                       { write_exp_elt_opcode (pstate, TYPE_INSTANCE);
+                        /* See above.  */
+                        write_exp_elt_longcst (pstate,
+                                               follow_type_instance_flags ());
                         write_exp_elt_longcst (pstate, 0);
                         write_exp_elt_longcst (pstate, 0);
                         write_exp_elt_opcode (pstate, TYPE_INSTANCE);
index 893e04d83f5849fc090ae09b23cac75ebe07cb5c..6678b33364d67f2bc7fb46488a0f6136acbd9a50 100644 (file)
@@ -8042,6 +8042,23 @@ free_delayed_list (void *ptr)
     }
 }
 
+/* Check whether [PHYSNAME, PHYSNAME+LEN) ends with a modifier like
+   "const" / "volatile".  If so, decrements LEN by the length of the
+   modifier and return true.  Otherwise return false.  */
+
+template<size_t N>
+static bool
+check_modifier (const char *physname, size_t &len, const char (&mod)[N])
+{
+  size_t mod_len = sizeof (mod) - 1;
+  if (len > mod_len && startswith (physname + (len - mod_len), mod))
+    {
+      len -= mod_len;
+      return true;
+    }
+  return false;
+}
+
 /* Compute the physnames of any methods on the CU's method list.
 
    The computation of method physnames is delayed in order to avoid the
@@ -8053,6 +8070,12 @@ compute_delayed_physnames (struct dwarf2_cu *cu)
 {
   int i;
   struct delayed_method_info *mi;
+
+  /* Only C++ delays computing physnames.  */
+  if (VEC_empty (delayed_method_info, cu->method_list))
+    return;
+  gdb_assert (cu->language == language_cplus);
+
   for (i = 0; VEC_iterate (delayed_method_info, cu->method_list, i, mi) ; ++i)
     {
       const char *physname;
@@ -8061,6 +8084,26 @@ compute_delayed_physnames (struct dwarf2_cu *cu)
       physname = dwarf2_physname (mi->name, mi->die, cu);
       TYPE_FN_FIELD_PHYSNAME (fn_flp->fn_fields, mi->index)
        = physname ? physname : "";
+
+      /* Since there's no tag to indicate whether a method is a
+        const/volatile overload, extract that information out of the
+        demangled name.  */
+      if (physname != NULL)
+       {
+         size_t len = strlen (physname);
+
+         while (1)
+           {
+             if (physname[len] == ')') /* shortcut */
+               break;
+             else if (check_modifier (physname, len, " const"))
+               TYPE_FN_FIELD_CONST (fn_flp->fn_fields, mi->index) = 1;
+             else if (check_modifier (physname, len, " volatile"))
+               TYPE_FN_FIELD_VOLATILE (fn_flp->fn_fields, mi->index) = 1;
+             else
+               break;
+           }
+       }
     }
 }
 
index 7d129f0e774c6149dadde635c05dac2cfee2bd17..5a434b9ceac989cbde19680239937377d15f9b37 100644 (file)
@@ -642,18 +642,22 @@ ptrmath_type_p (const struct language_defn *lang, struct type *type)
     }
 }
 
-/* Constructs a fake method with the given parameter types.
-   This function is used by the parser to construct an "expected"
-   type for method overload resolution.  */
+/* Constructs a fake method with the given parameter types.  This
+   function is used by the parser to construct an "expected" type for
+   method overload resolution.  FLAGS is used as instance flags of the
+   new type, in order to be able to make the new type represent a
+   const/volatile overload.  */
 
 static struct type *
-make_params (int num_types, struct type **param_types)
+make_params (type_instance_flags flags,
+            int num_types, struct type **param_types)
 {
   struct type *type = XCNEW (struct type);
   TYPE_MAIN_TYPE (type) = XCNEW (struct main_type);
   TYPE_LENGTH (type) = 1;
   TYPE_CODE (type) = TYPE_CODE_METHOD;
   TYPE_CHAIN (type) = type;
+  TYPE_INSTANCE_FLAGS (type) = flags;
   if (num_types > 0)
     {
       if (param_types[num_types - 1] == NULL)
@@ -2039,18 +2043,22 @@ evaluate_subexp_standard (struct type *expect_type,
        }
 
     case TYPE_INSTANCE:
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      arg_types = (struct type **) alloca (nargs * sizeof (struct type *));
-      for (ix = 0; ix < nargs; ++ix)
-       arg_types[ix] = exp->elts[pc + 1 + ix + 1].type;
-
-      expect_type = make_params (nargs, arg_types);
-      *(pos) += 3 + nargs;
-      arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
-      xfree (TYPE_FIELDS (expect_type));
-      xfree (TYPE_MAIN_TYPE (expect_type));
-      xfree (expect_type);
-      return arg1;
+      {
+       type_instance_flags flags
+         = (type_instance_flag_value) longest_to_int (exp->elts[pc + 1].longconst);
+       nargs = longest_to_int (exp->elts[pc + 2].longconst);
+       arg_types = (struct type **) alloca (nargs * sizeof (struct type *));
+       for (ix = 0; ix < nargs; ++ix)
+         arg_types[ix] = exp->elts[pc + 2 + ix + 1].type;
+
+       expect_type = make_params (flags, nargs, arg_types);
+       *(pos) += 4 + nargs;
+       arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
+       xfree (TYPE_FIELDS (expect_type));
+       xfree (TYPE_MAIN_TYPE (expect_type));
+       xfree (expect_type);
+       return arg1;
+      }
 
     case BINOP_CONCAT:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
index fad20e81519737d869428e4253c9790412bf7c1f..2c16b497fc06c1b8f2be04979e95b81fca7a2f7a 100644 (file)
@@ -543,11 +543,15 @@ print_subexp_standard (struct expression *exp, int *pos,
 
     case TYPE_INSTANCE:
       {
-       LONGEST count = exp->elts[pc + 1].longconst;
+       type_instance_flags flags
+         = (type_instance_flag_value) longest_to_int (exp->elts[pc + 1].longconst);
+       LONGEST count = exp->elts[pc + 2].longconst;
 
+       /* The FLAGS.  */
+       (*pos)++;
        /* The COUNT.  */
        (*pos)++;
-       fputs_unfiltered ("TypesInstance(", stream);
+       fputs_unfiltered ("TypeInstance(", stream);
        while (count-- > 0)
          {
            type_print (exp->elts[(*pos)++].type, "", stream, 0);
@@ -558,6 +562,12 @@ print_subexp_standard (struct expression *exp, int *pos,
        /* Ending COUNT and ending TYPE_INSTANCE.  */
        (*pos) += 2;
        print_subexp (exp, pos, stream, PREC_PREFIX);
+
+       if (flags & TYPE_INSTANCE_FLAG_CONST)
+         fputs_unfiltered (",const", stream);
+       if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
+         fputs_unfiltered (",volatile", stream);
+
        fputs_unfiltered (")", stream);
        return;
       }
@@ -1019,9 +1029,9 @@ dump_subexp_body_standard (struct expression *exp,
 
     case TYPE_INSTANCE:
       {
-       LONGEST len;
-
-       len = exp->elts[elt++].longconst;
+       type_instance_flags flags
+         = (type_instance_flag_value) longest_to_int (exp->elts[elt++].longconst);
+       LONGEST len = exp->elts[elt++].longconst;
        fprintf_filtered (stream, "%s TypeInstance: ", plongest (len));
        while (len-- > 0)
          {
@@ -1034,6 +1044,22 @@ dump_subexp_body_standard (struct expression *exp,
            if (len > 0)
              fputs_filtered (", ", stream);
          }
+
+       fprintf_filtered (stream, " Flags: %s (", hex_string (flags));
+       bool space = false;
+       auto print_one = [&] (const char *mod)
+         {
+           if (space)
+             fputs_filtered (" ", stream);
+           space = true;
+           fprintf_filtered (stream, mod);
+         };
+       if (flags & TYPE_INSTANCE_FLAG_CONST)
+         print_one ("const");
+       if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
+         print_one ("volatile");
+       fprintf_filtered (stream, ")");
+
        /* Ending LEN and ending TYPE_INSTANCE.  */
        elt += 2;
        elt = dump_subexp (exp, stream, elt);
index d2018a810800398ba8069bc599b172b9edde3659..9d9b09ffc9fa1c10e6ea28632b58c47ed737c607 100644 (file)
@@ -46,6 +46,7 @@
 
 #include "hashtab.h"
 #include "common/offset-type.h"
+#include "common/enum-flags.h"
 
 /* Forward declarations for prototypes.  */
 struct field;
@@ -196,6 +197,8 @@ enum type_instance_flag_value
   TYPE_INSTANCE_FLAG_ATOMIC = (1 << 8)
 };
 
+DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
+
 /* * Unsigned integer type.  If this is not set for a TYPE_CODE_INT,
    the type is signed (unless TYPE_NOSIGN (below) is set).  */
 
@@ -304,25 +307,25 @@ enum type_instance_flag_value
 /* * Constant type.  If this is set, the corresponding type has a
    const modifier.  */
 
-#define TYPE_CONST(t) (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_CONST)
+#define TYPE_CONST(t) ((TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_CONST) != 0)
 
 /* * Volatile type.  If this is set, the corresponding type has a
    volatile modifier.  */
 
 #define TYPE_VOLATILE(t) \
-  (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_VOLATILE)
+  ((TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_VOLATILE) != 0)
 
 /* * Restrict type.  If this is set, the corresponding type has a
    restrict modifier.  */
 
 #define TYPE_RESTRICT(t) \
-  (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_RESTRICT)
+  ((TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_RESTRICT) != 0)
 
 /* * Atomic type.  If this is set, the corresponding type has an
    _Atomic modifier.  */
 
 #define TYPE_ATOMIC(t) \
-  (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_ATOMIC)
+  ((TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_ATOMIC) != 0)
 
 /* * True if this type represents either an lvalue or lvalue reference type.  */
 
@@ -349,10 +352,10 @@ enum type_instance_flag_value
    is instruction space, and for data objects is data memory.  */
 
 #define TYPE_CODE_SPACE(t) \
-  (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_CODE_SPACE)
+  ((TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_CODE_SPACE) != 0)
 
 #define TYPE_DATA_SPACE(t) \
-  (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_DATA_SPACE)
+  ((TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_DATA_SPACE) != 0)
 
 /* * Address class flags.  Some environments provide for pointers
    whose size is different from that of a normal pointer or address
index e1fa229230c824d27901c51b93611ded51ec4d56..7971f6c78c7c589247bfc4b5808977edc5cfc0a5 100644 (file)
@@ -927,7 +927,7 @@ operator_length_standard (const struct expression *expr, int endpos,
       break;
 
     case TYPE_INSTANCE:
-      oplen = 4 + longest_to_int (expr->elts[endpos - 2].longconst);
+      oplen = 5 + longest_to_int (expr->elts[endpos - 2].longconst);
       args = 1;
       break;
 
@@ -1642,6 +1642,33 @@ push_typelist (VEC (type_ptr) *list)
   push_type (tp_function_with_arguments);
 }
 
+/* Pop the type stack and return a type_instance_flags that
+   corresponds the const/volatile qualifiers on the stack.  This is
+   called by the C++ parser when parsing methods types, and as such no
+   other kind of type in the type stack is expected.  */
+
+type_instance_flags
+follow_type_instance_flags ()
+{
+  type_instance_flags flags = 0;
+
+  for (;;)
+    switch (pop_type ())
+      {
+      case tp_end:
+       return flags;
+      case tp_const:
+       flags |= TYPE_INSTANCE_FLAG_CONST;
+       break;
+      case tp_volatile:
+       flags |= TYPE_INSTANCE_FLAG_VOLATILE;
+       break;
+      default:
+       gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
+      }
+}
+
+
 /* Pop the type stack and return the type which corresponds to FOLLOW_TYPE
    as modified by all the stuff on the stack.  */
 struct type *
@@ -1821,11 +1848,11 @@ operator_check_standard (struct expression *exp, int pos,
 
     case TYPE_INSTANCE:
       {
-       LONGEST arg, nargs = elts[pos + 1].longconst;
+       LONGEST arg, nargs = elts[pos + 2].longconst;
 
        for (arg = 0; arg < nargs; arg++)
          {
-           struct type *type = elts[pos + 2 + arg].type;
+           struct type *type = elts[pos + 3 + arg].type;
            struct objfile *objfile = TYPE_OBJFILE (type);
 
            if (objfile && (*objfile_func) (objfile, data))
index fadc2ef2b13d0ca00d7c9d8485546a57f6c42919..f7ba7f088cac857328ab12ab3c9884a729e7f022 100644 (file)
@@ -266,6 +266,8 @@ extern const char *op_name_standard (enum exp_opcode);
 
 extern struct type *follow_types (struct type *);
 
+extern type_instance_flags follow_type_instance_flags ();
+
 extern void null_post_parser (struct expression **, int);
 
 extern int parse_float (const char *p, int len, DOUBLEST *d,
index ddea68bd53e672362bb7fb83e6f92ef09b137204..e53192283eaa515c3f25f7027e8f3f64dbc253cd 100644 (file)
@@ -1,3 +1,15 @@
+2017-09-04  Pedro Alves  <palves@redhat.com>
+
+       * gdb.base/func-static.c (S::method const, S::method volatile)
+       (S::method volatile const): New methods.
+       (c_s, v_s, cv_s): New instances.
+       (main): Call method() on them.
+       * gdb.base/func-static.exp (syntax_re, cannot_resolve_re): New variables.
+       (cannot_resolve): New procedure.
+       (cxx_scopes_list): Test cv methods.  Add print-scope-quote and
+       print-quote-unquoted columns.
+       (do_test): Test printing each scope too.
+
 2017-09-04  Pedro Alves  <palves@redhat.com>
 
        * gdb.base/local-static.exp: Also test with
index 5bfff8d662dea3afe64b00825e6c78674a93c5c6..0f4c4f0b5f12c996e5c446ada5ca0fec20c071dc 100644 (file)
@@ -53,10 +53,17 @@ struct S
   }
 
   void method ();
+  void method () const;
+  void method () volatile;
+  void method () volatile const;
+
   static void static_method ();
 };
 
 S s;
+const S c_s = {};
+volatile S v_s = {};
+const volatile S cv_s = {};
 
 void
 S::method ()
@@ -64,6 +71,24 @@ S::method ()
   DEF_STATICS (S_M);
 }
 
+void
+S::method () const
+{
+  DEF_STATICS (S_M_C);
+}
+
+void
+S::method () volatile
+{
+  DEF_STATICS (S_M_V);
+}
+
+void
+S::method () const volatile
+{
+  DEF_STATICS (S_M_CV);
+}
+
 void
 S::static_method ()
 {
@@ -127,6 +152,9 @@ main ()
 
 #ifdef __cplusplus
       s.method ();
+      c_s.method ();
+      v_s.method ();
+      cv_s.method ();
       s.inline_method ();
       S::static_method ();
       S::static_inline_method ();
index 581efa396aa98d47cba1f62e0f0893cc97565883..5e8eaaa9741413e5fba1b3aadc81ab3e0acfc76a 100644 (file)
 
 standard_testfile .c
 
+# A few expected errors.
+set syntax_re "A syntax error in expression, near.*"
+set cannot_resolve_re "Cannot resolve method S::method to any overloaded instance"
+
+# Build an "Cannot resolve method ..." expected error string for
+# method METH.
+#
+proc cannot_resolve {meth} {
+    return "Cannot resolve method $meth to any overloaded instance"
+}
+
 # A list of scopes that have the static variables that we want to
 # print.  Each entry has, in order, the scope/function name, and the
-# prefix used by the static variables.  (The prefix exists to make it
-# easier to debug the test if something goes wrong.)
-
-     #SCOPE                            #PREFIX
+# prefix used by the static variables.  The prefix exists both to make
+# it easier to debug the test if something goes wrong, and, to make
+# sure that printing the static local of one method overload doesn't
+# find the variables of the wrong overload.
+#
+# While at it, we also try printing each scope without the static
+# local, to check that the parse copes with cv overloads without
+# quoting.  That's what the third and forth columns are for.  Note
+# that printing "func()" is different from "func(void)".  The former
+# is an inferior function call, while the latter is a reference to the
+# function.
+
+     #SCOPE                            #PREFIX         #PRINT-SCOPE-QUOTED
+                                                       #PRINT-SCOPE-UNQUOTED (opt)
 set cxx_scopes_list {
-    {"S::method()"                     "S_M"}
-    {"S::static_method()"              "S_SM"}
-    {"S::inline_method()"              "S_IM"}
-    {"S::static_inline_method()"       "S_SIM"}
-    {"S2<int>::method()"               "S2_M"}
-    {"S2<int>::static_method()"                "S2_SM"}
-    {"S2<int>::inline_method()"                "S2_IM"}
-    {"S2<int>::static_inline_method()" "S2_SIM"}
-    {"free_func()"                     "FF"}
-    {"free_inline_func()"              "FIF"}
+    {"S::method()"                     "S_M"           {= \\{void \\(S \\* const\\)\\} $hex <S::method\\(\\)>}
+                                                       {[cannot_resolve "S::method"]}}
+
+    {"S::method() const"               "S_M_C"         {= \\{void \\(const S \\* const\\)\\} $hex <S::method\\(\\) const>}
+                                                       $syntax_re}
+
+    {"S::method() volatile"            "S_M_V"         {= \\{void \\(volatile S \\* const\\)\\} $hex <S::method\\(\\) volatile>}
+                                                       $syntax_re}
+
+    {"S::method() const volatile"      "S_M_CV"        {= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}
+                                                       $syntax_re}
+
+    {"S::method() volatile const"      "S_M_CV"        {= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}
+                                                       $syntax_re}
+
+    {"S::method(void)"                 "S_M"           {= \\{void \\(S \\* const\\)\\} $hex <S::method\\(\\)>}}
+    {"S::method(void) const"           "S_M_C"         {= \\{void \\(const S \\* const\\)\\} $hex <S::method\\(\\) const>}}
+    {"S::method(void) volatile"                "S_M_V"         {= \\{void \\(volatile S \\* const\\)\\} $hex <S::method\\(\\) volatile>}}
+    {"S::method(void) const volatile"  "S_M_CV"        {= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}}
+    {"S::method(void) volatile const"  "S_M_CV"        {= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}}
+
+    {"S::static_method()"              "S_SM"          {= \\{void \\(void\\)\\} $hex <S::static_method\\(\\)>}
+                                                       "void"}
+
+    {"S::static_method(void)"          "S_SM"          {= \\{void \\(void\\)\\} $hex <S::static_method\\(\\)>}}
+
+    {"S::inline_method()"              "S_IM"          {= \\{void \\(S \\* const\\)\\} $hex <S::inline_method\\(\\)>}
+                                                       {[cannot_resolve "S::inline_method"]}}
+
+    {"S::inline_method(void)"          "S_IM"          {= \\{void \\(S \\* const\\)\\} $hex <S::inline_method\\(\\)>}}
+
+    {"S::static_inline_method()"       "S_SIM"         {= \\{void \\(void\\)\\} $hex <S::static_inline_method\\(\\)>}
+                                                       "void"}
+
+    {"S::static_inline_method(void)"   "S_SIM"         {= \\{void \\(void\\)\\} $hex <S::static_inline_method\\(\\)>}}
+
+    {"S2<int>::method()"               "S2_M"          {= \\{void \\(S2<int> \\* const\\)\\} $hex <S2<int>::method\\(\\)>}
+                                                       {[cannot_resolve "S2<int>::method"]}}
+
+    {"S2<int>::static_method()"                "S2_SM"         {= \\{void \\(void\\)\\} $hex <S2<int>::static_method\\(\\)>}
+                                                       "void"}
+
+    {"S2<int>::inline_method()"                "S2_IM"         {= \\{void \\(S2<int> \\* const\\)\\} $hex <S2<int>::inline_method\\(\\)>}
+                                                       {[cannot_resolve "S2<int>::inline_method"]}}
+
+    {"S2<int>::static_inline_method()" "S2_SIM"        {= \\{void \\(void\\)\\} $hex <S2<int>::static_inline_method\\(\\)>}
+                                                       "void"}
+
+    {"free_func"                       "FF"            {= \\{void \\(void\\)\\} $hex <free_func\\(\\)>}}
+
+    {"free_func()"                     "FF"            {= \\{void \\(void\\)\\} $hex <free_func\\(\\)>}
+                                                       "void"}
+
+    {"free_func(void)"                 "FF"            {= \\{void \\(void\\)\\} $hex <free_func\\(\\)>}}
+
+    {"free_inline_func()"              "FIF"           {= \\{void \\(void\\)\\} $hex <free_inline_func\\(\\)>}
+                                                       "void"}
+
+    {"free_inline_func(void)"          "FIF"           {= \\{void \\(void\\)\\} $hex <free_inline_func\\(\\)>}}
 }
 
 set c_scopes_list {
-    {"free_func"                       "FF"}
-    {"free_inline_func"                        "FIF"}
+    {"free_func"                       "FF"            {= \\{void \\(void\\)\\} $hex <free_func>}}
+    {"free_inline_func"                        "FIF"           {= \\{void \\(void\\)\\} $hex <free_inline_func>}}
 }
 
 # A list of all the static varibles defined in each scope.  The first
@@ -91,6 +161,29 @@ proc do_test {lang} {
        set scopes_list $cxx_scopes_list
     }
 
+    # Print each scope/function using these syntaxes:
+    #
+    #  "(gdb) p 'S::method() const'"    # quoted
+    #  "(gdb) p S::method() const"      # unquoted
+    #
+    foreach scope_line $scopes_list  {
+       set scope [lindex $scope_line 0]
+
+       set print_quoted_re [lindex $scope_line 2]
+       set print_quoted_re [uplevel 1 "subst -nobackslashes -nocommands \"$print_quoted_re\""]
+
+       set print_unquoted_re [lindex $scope_line 3]
+       set print_unquoted_re [uplevel 1 "subst -nobackslashes -nocommands \"$print_unquoted_re\""]
+
+       gdb_test "print '${scope}'" $print_quoted_re
+
+       if {$print_unquoted_re != ""} {
+           gdb_test "print ${scope}" $print_unquoted_re
+       } else {
+           gdb_test "print ${scope}" $print_quoted_re
+       }
+    }
+
     # Print each variable using these syntaxes:
     #
     #  'func()'::var
index f5e3aabbf8f70f8c170efdf82ea1d443385abb99..19f96c8ddc5725ae77108f36883609723450addb 100644 (file)
@@ -3424,6 +3424,11 @@ value_struct_elt_for_reference (struct type *domain, int offset,
            {
              for (j = 0; j < len; ++j)
                {
+                 if (TYPE_CONST (intype) != TYPE_FN_FIELD_CONST (f, j))
+                   continue;
+                 if (TYPE_VOLATILE (intype) != TYPE_FN_FIELD_VOLATILE (f, j))
+                   continue;
+
                  if (compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype, 0)
                      || compare_parameters (TYPE_FN_FIELD_TYPE (f, j),
                                             intype, 1))