infcall, c++: allow more info to be computed for pass-by-reference values
authorTankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Fri, 20 Dec 2019 16:43:06 +0000 (17:43 +0100)
committerTankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Fri, 20 Dec 2019 16:43:06 +0000 (17:43 +0100)
In C++, call-by-value arguments that cannot be trivially copied are
implicitly passed by reference.  When making an infcall, GDB needs to
find out if an argument is pass-by-reference or not, so that the
correct semantics can be followed.  This patch enriches the
information computed by the language ops for pass-by-reference
arguments.  Instead of a plain binary result, the computed information
now includes whether the argument is

  - copy constructible
  - destructible
  - trivially copyable
  - trivially copy constructible
  - trivially destructible

This information is stored in a struct named 'language_pass_by_ref_info'.

This patch paves the way for GDB's infcall mechanism to call the copy
ctor and the destructor of a pass-by-ref argument appropriately.

gdb/ChangeLog:
2019-12-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

* language.h (struct language_pass_by_ref_info): New struct.
(struct language_defn)<la_pass_by_reference>: Change the signature
to return a language_pass_by_ref_info instead of an int.
(language_pass_by_reference): Ditto.
(default_pass_by_reference): Ditto.
Adjust the users listed below.
* arch-utils.c (default_return_in_first_hidden_param_p):
Update.
* cp-abi.c (cp_pass_by_reference): Update.
* cp-abi.h (cp_pass_by_reference): Update declaration.
(struct cp_abi_ops)<pass_by_reference>: Update.
* gnu-v3-abi.c (gnuv3_pass_by_reference): Update.
* infcall.c (call_function_by_hand_dummy): Update.
* language.c (language_pass_by_reference): Update.
(default_pass_by_reference): Update.
* tic6x-tdep.c (tic6x_return_value): Update.

Change-Id: Ib1c1f87f2490a5737c469f7b7185ddc7f6a164cb

gdb/ChangeLog
gdb/arch-utils.c
gdb/cp-abi.c
gdb/cp-abi.h
gdb/gnu-v3-abi.c
gdb/infcall.c
gdb/language.c
gdb/language.h
gdb/tic6x-tdep.c

index 5175ebcc2566e08832d34fbb7667aacc10ea03d5..3e88754f80154e518704a4c2e111838297e888d0 100644 (file)
@@ -1,3 +1,22 @@
+2019-12-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
+
+       * language.h (struct language_pass_by_ref_info): New struct.
+       (struct language_defn)<la_pass_by_reference>: Change the signature
+       to return a language_pass_by_ref_info instead of an int.
+       (language_pass_by_reference): Ditto.
+       (default_pass_by_reference): Ditto.
+       Adjust the users listed below.
+       * arch-utils.c (default_return_in_first_hidden_param_p):
+       Update.
+       * cp-abi.c (cp_pass_by_reference): Update.
+       * cp-abi.h (cp_pass_by_reference): Update declaration.
+       (struct cp_abi_ops)<pass_by_reference>: Update.
+       * gnu-v3-abi.c (gnuv3_pass_by_reference): Update.
+       * infcall.c (call_function_by_hand_dummy): Update.
+       * language.c (language_pass_by_reference): Update.
+       (default_pass_by_reference): Update.
+       * tic6x-tdep.c (tic6x_return_value): Update.
+
 2019-12-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
 
        * dwarf2read.c (dwarf2_add_member_fn): Read the DW_AT_defaulted
index 2129c3b2c388670b6f52e85ba62a1370b9a1dad0..a1a003f91f1c812abd3597753d771ac5381e6e90 100644 (file)
@@ -858,7 +858,7 @@ default_return_in_first_hidden_param_p (struct gdbarch *gdbarch,
   /* Usually, the return value's address is stored the in the "first hidden"
      parameter if the return value should be passed by reference, as
      specified in ABI.  */
-  return language_pass_by_reference (type);
+  return !(language_pass_by_reference (type).trivially_copyable);
 }
 
 int default_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr)
index bbb74d426382fa0662d8b78340e5dc51793fb51f..6503b4c160bb377447749a42b3dd904f724a2261 100644 (file)
@@ -220,11 +220,13 @@ cplus_typename_from_type_info (struct value *value)
   return (*current_cp_abi.get_typename_from_type_info) (value);
 }
 
-int
+/* See cp-abi.h.  */
+
+struct language_pass_by_ref_info
 cp_pass_by_reference (struct type *type)
 {
   if ((current_cp_abi.pass_by_reference) == NULL)
-    return 0;
+    return default_pass_by_reference (type);
   return (*current_cp_abi.pass_by_reference) (type);
 }
 
index 3cbf19cd511791c563263a2ecdfdd64ce885edc7..cc77e0b06328a2ef9b089bce182187508e55c09d 100644 (file)
@@ -207,9 +207,11 @@ extern std::string cplus_typename_from_type_info (struct value *value);
 CORE_ADDR cplus_skip_trampoline (struct frame_info *frame,
                                 CORE_ADDR stop_pc);
 
-/* Return non-zero if an argument of type TYPE should be passed by
-   reference instead of value.  */
-extern int cp_pass_by_reference (struct type *type);
+/* Return a struct that provides pass-by-reference information
+   about the given TYPE.  */
+
+extern struct language_pass_by_ref_info cp_pass_by_reference
+  (struct type *type);
 
 struct cp_abi_ops
 {
@@ -246,7 +248,7 @@ struct cp_abi_ops
   struct type *(*get_type_from_type_info) (struct value *value);
   std::string (*get_typename_from_type_info) (struct value *value);
   CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR);
-  int (*pass_by_reference) (struct type *type);
+  struct language_pass_by_ref_info (*pass_by_reference) (struct type *type);
 };
 
 
index d630ec07b11175e8a4610bf79e88a5d5c569ad5b..35197e56334799afed24b45b28e7bbb677fefb53 100644 (file)
@@ -1230,7 +1230,7 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
   return real_stop_pc;
 }
 
-/* Return nonzero if a type should be passed by reference.
+/* Return pass-by-reference information for the given TYPE.
 
    The rule in the v3 ABI document comes from section 3.1.1.  If the
    type has a non-trivial copy constructor or destructor, then the
@@ -1248,22 +1248,33 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
 
    We don't do anything with the constructors or destructors,
    but we have to get the argument passing right anyway.  */
-static int
+
+static struct language_pass_by_ref_info
 gnuv3_pass_by_reference (struct type *type)
 {
   int fieldnum, fieldelem;
 
   type = check_typedef (type);
 
+  /* Start with the default values.  */
+  struct language_pass_by_ref_info info
+    = default_pass_by_reference (type);
+
+  /* FIXME: Currently, this implementation only fills in the
+     'trivially-copyable' field to preserve GDB's existing behavior.  */
+
   /* We're only interested in things that can have methods.  */
   if (TYPE_CODE (type) != TYPE_CODE_STRUCT
       && TYPE_CODE (type) != TYPE_CODE_UNION)
-    return 0;
+    return info;
 
   /* A dynamic class has a non-trivial copy constructor.
      See c++98 section 12.8 Copying class objects [class.copy].  */
   if (gnuv3_dynamic_class (type))
-    return 1;
+    {
+      info.trivially_copyable = false;
+      return info;
+    }
 
   for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
     for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
@@ -1280,7 +1291,10 @@ gnuv3_pass_by_reference (struct type *type)
 
        /* If we've found a destructor, we must pass this by reference.  */
        if (name[0] == '~')
-         return 1;
+         {
+           info.trivially_copyable = false;
+           return info;
+         }
 
        /* If the mangled name of this method doesn't indicate that it
           is a constructor, we're not interested.
@@ -1302,11 +1316,13 @@ gnuv3_pass_by_reference (struct type *type)
 
            if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
              {
-               struct type *arg_target_type;
-
-               arg_target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
+               struct type *arg_target_type
+                 = check_typedef (TYPE_TARGET_TYPE (arg_type));
                if (class_types_same_p (arg_target_type, type))
-                 return 1;
+                 {
+                   info.trivially_copyable = false;
+                   return info;
+                 }
              }
          }
       }
@@ -1319,11 +1335,18 @@ gnuv3_pass_by_reference (struct type *type)
      about recursive loops here, since we are only looking at members
      of complete class type.  Also ignore any static members.  */
   for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++)
-    if (! field_is_static (&TYPE_FIELD (type, fieldnum))
-        && gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum)))
-      return 1;
+    if (!field_is_static (&TYPE_FIELD (type, fieldnum)))
+      {
+       struct language_pass_by_ref_info field_info
+         = gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum));
+       if (!field_info.trivially_copyable)
+         {
+           info.trivially_copyable = false;
+           return info;
+         }
+      }
 
-  return 0;
+  return info;
 }
 
 static void
index 5553fc9779179b32504b8382ee168437b0dd960f..f3664d508041496def13634fdc962bf075fc8fcb 100644 (file)
@@ -1020,7 +1020,8 @@ call_function_by_hand_dummy (struct value *function,
       args[i] = value_arg_coerce (gdbarch, args[i],
                                  param_type, prototyped);
 
-      if (param_type != NULL && language_pass_by_reference (param_type))
+      if (param_type != NULL
+         && !(language_pass_by_reference (param_type).trivially_copyable))
        args[i] = value_addr (args[i]);
     }
 
index 76efc497379bf479aba7abdeeed1137ba3c95189..ac74c7ffa3143a9e7e4be6a6cbc8318b420ac268 100644 (file)
@@ -652,21 +652,23 @@ language_class_name_from_physname (const struct language_defn *lang,
   return NULL;
 }
 
-/* Return non-zero if TYPE should be passed (and returned) by
-   reference at the language level.  */
-int
+/* Return information about whether TYPE should be passed
+   (and returned) by reference at the language level.  */
+
+struct language_pass_by_ref_info
 language_pass_by_reference (struct type *type)
 {
   return current_language->la_pass_by_reference (type);
 }
 
-/* Return zero; by default, types are passed by value at the language
-   level.  The target ABI may pass or return some structs by reference
-   independent of this.  */
-int
+/* Return a default struct that provides pass-by-reference information
+   about the given TYPE.  Languages should update the default values
+   as appropriate.  */
+
+struct language_pass_by_ref_info
 default_pass_by_reference (struct type *type)
 {
-  return 0;
+  return {};
 }
 
 /* Return the default string containing the list of characters
index 14d6fac30371313efc70c5c7316c751ff838b52a..f6cd29b6709c271aed446c135f6eebb0f9e0ed46 100644 (file)
@@ -128,6 +128,47 @@ struct language_arch_info
   struct type *bool_type_default;
 };
 
+/* In a language (particularly C++) a function argument of an aggregate
+   type (i.e.  class/struct/union) may be implicitly passed by reference
+   even though it is declared a call-by-value argument in the source.
+   The struct below puts together necessary information for GDB to be
+   able to detect and carry out pass-by-reference semantics for a
+   particular type.  This type is referred as T in the inlined comments
+   below.
+
+   The default values of the fields are chosen to give correct semantics
+   for primitive types and for simple aggregate types, such as
+
+   class T {
+     int x;
+   };  */
+
+struct language_pass_by_ref_info
+{
+  /* True if an argument of type T can be passed to a function by value
+     (i.e.  not through an implicit reference).  False, otherwise.  */
+  bool trivially_copyable = true;
+
+  /* True if a copy of a value of type T can be initialized by
+     memcpy'ing the value bit-by-bit.  False, otherwise.
+     E.g.  If T has a user-defined copy ctor, this should be false.  */
+  bool trivially_copy_constructible = true;
+
+  /* True if a value of type T can be destructed simply by reclaiming
+     the memory area occupied by the value.  False, otherwise.
+     E.g.  If T has a user-defined destructor, this should be false.  */
+  bool trivially_destructible = true;
+
+  /* True if it is allowed to create a copy of a value of type T.
+     False, otherwise.
+     E.g.  If T has a deleted copy ctor, this should be false.  */
+  bool copy_constructible = true;
+
+  /* True if a value of type T can be destructed.  False, otherwise.
+     E.g.  If T has a deleted destructor, this should be false.  */
+  bool destructible = true;
+};
+
 /* Structure tying together assorted information about a language.  */
 
 struct language_defn
@@ -356,9 +397,10 @@ struct language_defn
                                   struct ui_file *stream,
                                   const struct value_print_options *options);
 
-    /* Return non-zero if TYPE should be passed (and returned) by
-       reference at the language level.  */
-    int (*la_pass_by_reference) (struct type *type);
+    /* Return information about whether TYPE should be passed
+       (and returned) by reference at the language level.  */
+    struct language_pass_by_ref_info (*la_pass_by_reference)
+      (struct type *type);
 
     /* Return an expression that can be used for a location
        watchpoint.  TYPE is a pointer type that points to the memory
@@ -613,14 +655,14 @@ extern void default_print_array_index (struct value *index_value,
                                        struct ui_file *stream,
                                       const struct value_print_options *options);
 
-/* Return non-zero if TYPE should be passed (and returned) by
-   reference at the language level.  */
-int language_pass_by_reference (struct type *type);
+/* Return information about whether TYPE should be passed
+   (and returned) by reference at the language level.  */
+struct language_pass_by_ref_info language_pass_by_reference (struct type *type);
 
-/* Return zero; by default, types are passed by value at the language
-   level.  The target ABI may pass or return some structs by reference
-   independent of this.  */
-int default_pass_by_reference (struct type *type);
+/* Return a default struct that provides pass-by-reference information
+   about the given TYPE.  Languages should update the default values
+   as appropriate.  */
+struct language_pass_by_ref_info default_pass_by_reference (struct type *type);
 
 /* The default implementation of la_print_typedef.  */
 void default_print_typedef (struct type *type, struct symbol *new_symbol,
index 2df83c4f61970da91dc4f145fba2460681b5d3ec..ca059f91b58032c20acccdae5a994e7faba05cf5 100644 (file)
@@ -784,7 +784,7 @@ tic6x_return_value (struct gdbarch *gdbarch, struct value *function,
       if (type != NULL)
        {
          type = check_typedef (type);
-         if (language_pass_by_reference (type))
+         if (!(language_pass_by_reference (type).trivially_copyable))
            return RETURN_VALUE_STRUCT_CONVENTION;
        }
     }