]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/gnu-v3-abi.c
gdb: add back declarations for _initialize functions
[thirdparty/binutils-gdb.git] / gdb / gnu-v3-abi.c
index 15c7c66700133c119e7b556946f5b886c17761cb..89574ec9ed51a6eb3a2f067aa356744ba41face0 100644 (file)
@@ -1,7 +1,7 @@
 /* Abstraction of GNU v3 abi.
    Contributed by Jim Blandy <jimb@redhat.com>
 
-   Copyright (C) 2001-2019 Free Software Foundation, Inc.
+   Copyright (C) 2001-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "cp-abi.h"
 #include "cp-support.h"
 #include "demangle.h"
+#include "dwarf2.h"
 #include "objfiles.h"
 #include "valprint.h"
 #include "c-lang.h"
 #include "typeprint.h"
 #include <algorithm>
+#include "cli/cli-style.h"
 
 static struct cp_abi_ops gnu_v3_abi_ops;
 
@@ -327,7 +329,7 @@ gnuv3_rtti_type (struct value *value,
      If we didn't like this approach, we could instead look in the
      type_info object itself to get the class name.  But this way
      should work just as well, and doesn't read target memory.  */
-  vtable_symbol_name = MSYMBOL_DEMANGLED_NAME (vtable_symbol);
+  vtable_symbol_name = vtable_symbol->demangled_name ();
   if (vtable_symbol_name == NULL
       || !startswith (vtable_symbol_name, "vtable for "))
     {
@@ -392,7 +394,7 @@ gnuv3_get_virtual_fn (struct gdbarch *gdbarch, struct value *container,
   /* If this architecture uses function descriptors directly in the vtable,
      then the address of the vtable entry is actually a "function pointer"
      (i.e. points to the descriptor).  We don't need to scale the index
-     by the size of a function descriptor; GCC does that before outputing
+     by the size of a function descriptor; GCC does that before outputting
      debug information.  */
   if (gdbarch_vtable_function_descriptors (gdbarch))
     vfn = value_addr (vfn);
@@ -677,7 +679,7 @@ gnuv3_make_method_ptr (struct type *type, gdb_byte *contents,
 {
   struct gdbarch *gdbarch = get_type_arch (type);
   int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order = type_byte_order (type);
 
   /* FIXME drow/2006-12-24: The adjustment of "this" is currently
      always zero, since the method pointer is of the correct type.
@@ -906,16 +908,16 @@ print_one_vtable (struct gdbarch *gdbarch, struct value *value,
       if (gdbarch_vtable_function_descriptors (gdbarch))
        vfn = value_addr (vfn);
 
-      TRY
+      try
        {
          addr = value_as_address (vfn);
        }
-      CATCH (ex, RETURN_MASK_ERROR)
+      catch (const gdb_exception_error &ex)
        {
-         printf_filtered (_("<error: %s>"), ex.message);
+         fprintf_styled (gdb_stdout, metadata_style.style (),
+                         _("<error: %s>"), ex.what ());
          got_error = 1;
        }
-      END_CATCH
 
       if (!got_error)
        print_function_pointer_address (opts, gdbarch, addr, gdb_stdout);
@@ -1147,11 +1149,11 @@ gnuv3_get_typename_from_type_info (struct value *type_info_ptr)
 
 #define TYPEINFO_PREFIX "typeinfo for "
 #define TYPEINFO_PREFIX_LEN (sizeof (TYPEINFO_PREFIX) - 1)
-  symname = MSYMBOL_DEMANGLED_NAME (typeinfo_sym.minsym);
+  symname = typeinfo_sym.minsym->demangled_name ();
   if (symname == NULL || strncmp (symname, TYPEINFO_PREFIX,
                                  TYPEINFO_PREFIX_LEN))
     error (_("typeinfo symbol '%s' has unexpected name"),
-          MSYMBOL_LINKAGE_NAME (typeinfo_sym.minsym));
+          typeinfo_sym.minsym->linkage_name ());
   class_name = symname + TYPEINFO_PREFIX_LEN;
 
   /* Strip off @plt and version suffixes.  */
@@ -1201,7 +1203,7 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
   /* The symbol's demangled name should be something like "virtual
      thunk to FUNCTION", where FUNCTION is the name of the function
      being thunked to.  */
-  thunk_name = MSYMBOL_DEMANGLED_NAME (thunk_sym.minsym);
+  thunk_name = thunk_sym.minsym->demangled_name ();
   if (thunk_name == NULL || strstr (thunk_name, " thunk to ") == NULL)
     return 0;
 
@@ -1229,7 +1231,128 @@ 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.
+/* A member function is in one these states.  */
+
+enum definition_style
+{
+  DOES_NOT_EXIST_IN_SOURCE,
+  DEFAULTED_INSIDE,
+  DEFAULTED_OUTSIDE,
+  DELETED,
+  EXPLICIT,
+};
+
+/* Return how the given field is defined.  */
+
+static definition_style
+get_def_style (struct fn_field *fn, int fieldelem)
+{
+  if (TYPE_FN_FIELD_DELETED (fn, fieldelem))
+    return DELETED;
+
+  if (TYPE_FN_FIELD_ARTIFICIAL (fn, fieldelem))
+    return DOES_NOT_EXIST_IN_SOURCE;
+
+  switch (TYPE_FN_FIELD_DEFAULTED (fn, fieldelem))
+    {
+    case DW_DEFAULTED_no:
+      return EXPLICIT;
+    case DW_DEFAULTED_in_class:
+      return DEFAULTED_INSIDE;
+    case DW_DEFAULTED_out_of_class:
+      return DEFAULTED_OUTSIDE;
+    default:
+      break;
+    }
+
+  return EXPLICIT;
+}
+
+/* Helper functions to determine whether the given definition style
+   denotes that the definition is user-provided or implicit.
+   Being defaulted outside the class decl counts as an explicit
+   user-definition, while being defaulted inside is implicit.  */
+
+static bool
+is_user_provided_def (definition_style def)
+{
+  return def == EXPLICIT || def == DEFAULTED_OUTSIDE;
+}
+
+static bool
+is_implicit_def (definition_style def)
+{
+  return def == DOES_NOT_EXIST_IN_SOURCE || def == DEFAULTED_INSIDE;
+}
+
+/* Helper function to decide if METHOD_TYPE is a copy/move
+   constructor type for CLASS_TYPE.  EXPECTED is the expected
+   type code for the "right-hand-side" argument.
+   This function is supposed to be used by the IS_COPY_CONSTRUCTOR_TYPE
+   and IS_MOVE_CONSTRUCTOR_TYPE functions below.  Normally, you should
+   not need to call this directly.  */
+
+static bool
+is_copy_or_move_constructor_type (struct type *class_type,
+                                 struct type *method_type,
+                                 type_code expected)
+{
+  /* The method should take at least two arguments...  */
+  if (TYPE_NFIELDS (method_type) < 2)
+    return false;
+
+  /* ...and the second argument should be the same as the class
+     type, with the expected type code...  */
+  struct type *arg_type = TYPE_FIELD_TYPE (method_type, 1);
+
+  if (TYPE_CODE (arg_type) != expected)
+    return false;
+
+  struct type *target = check_typedef (TYPE_TARGET_TYPE (arg_type));
+  if (!(class_types_same_p (target, class_type)))
+    return false;
+
+  /* ...and if any of the remaining arguments don't have a default value
+     then this is not a copy or move constructor, but just a
+     constructor.  */
+  for (int i = 2; i < TYPE_NFIELDS (method_type); i++)
+    {
+      arg_type = TYPE_FIELD_TYPE (method_type, i);
+      /* FIXME aktemur/2019-10-31: As of this date, neither
+        clang++-7.0.0 nor g++-8.2.0 produce a DW_AT_default_value
+        attribute.  GDB is also not set to read this attribute, yet.
+        Hence, we immediately return false if there are more than
+        2 parameters.
+        GCC bug link:
+        https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42959
+      */
+      return false;
+    }
+
+  return true;
+}
+
+/* Return true if METHOD_TYPE is a copy ctor type for CLASS_TYPE.  */
+
+static bool
+is_copy_constructor_type (struct type *class_type,
+                         struct type *method_type)
+{
+  return is_copy_or_move_constructor_type (class_type, method_type,
+                                          TYPE_CODE_REF);
+}
+
+/* Return true if METHOD_TYPE is a move ctor type for CLASS_TYPE.  */
+
+static bool
+is_move_constructor_type (struct type *class_type,
+                         struct type *method_type)
+{
+  return is_copy_or_move_constructor_type (class_type, method_type,
+                                          TYPE_CODE_RVALUE_REF);
+}
+
+/* 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
@@ -1237,32 +1360,60 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
    is one or perform the copy itself otherwise), pass the address of
    the copy, and then destroy the temporary (if necessary).
 
-   For return values with non-trivial copy constructors or
+   For return values with non-trivial copy/move constructors or
    destructors, space will be allocated in the caller, and a pointer
    will be passed as the first argument (preceding "this").
 
    We don't have a bulletproof mechanism for determining whether a
-   constructor or destructor is trivial.  For GCC and DWARF2 debug
-   information, we can check the artificial flag.
+   constructor or destructor is trivial.  For GCC and DWARF5 debug
+   information, we can check the calling_convention attribute,
+   the 'artificial' flag, the 'defaulted' attribute, and the
+   'deleted' attribute.  */
 
-   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);
+
+  bool has_cc_attr = false;
+  bool is_pass_by_value = false;
+  bool is_dynamic = false;
+  definition_style cctor_def = DOES_NOT_EXIST_IN_SOURCE;
+  definition_style dtor_def = DOES_NOT_EXIST_IN_SOURCE;
+  definition_style mctor_def = DOES_NOT_EXIST_IN_SOURCE;
+
   /* 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;
+
+  /* The compiler may have emitted the calling convention attribute.
+     Note: GCC does not produce this attribute as of version 9.2.1.
+     Bug link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92418  */
+  if (TYPE_CPLUS_CALLING_CONVENTION (type) == DW_CC_pass_by_value)
+    {
+      has_cc_attr = true;
+      is_pass_by_value = true;
+      /* Do not return immediately.  We have to find out if this type
+        is copy_constructible and destructible.  */
+    }
+
+  if (TYPE_CPLUS_CALLING_CONVENTION (type) == DW_CC_pass_by_reference)
+    {
+      has_cc_attr = true;
+      is_pass_by_value = false;
+    }
 
   /* 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;
+    is_dynamic = true;
 
   for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
     for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
@@ -1272,44 +1423,75 @@ gnuv3_pass_by_reference (struct type *type)
        const char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum);
        struct type *fieldtype = TYPE_FN_FIELD_TYPE (fn, fieldelem);
 
-       /* If this function is marked as artificial, it is compiler-generated,
-          and we assume it is trivial.  */
-       if (TYPE_FN_FIELD_ARTIFICIAL (fn, fieldelem))
-         continue;
-
-       /* If we've found a destructor, we must pass this by reference.  */
        if (name[0] == '~')
-         return 1;
-
-       /* If the mangled name of this method doesn't indicate that it
-          is a constructor, we're not interested.
-
-          FIXME drow/2007-09-23: We could do this using the name of
-          the method and the name of the class instead of dealing
-          with the mangled name.  We don't have a convenient function
-          to strip off both leading scope qualifiers and trailing
-          template arguments yet.  */
-       if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem))
-           && !TYPE_FN_FIELD_CONSTRUCTOR (fn, fieldelem))
-         continue;
-
-       /* If this method takes two arguments, and the second argument is
-          a reference to this class, then it is a copy constructor.  */
-       if (TYPE_NFIELDS (fieldtype) == 2)
          {
-           struct type *arg_type = TYPE_FIELD_TYPE (fieldtype, 1);
-
-           if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
+           /* We've found a destructor.
+              There should be at most one dtor definition.  */
+           gdb_assert (dtor_def == DOES_NOT_EXIST_IN_SOURCE);
+           dtor_def = get_def_style (fn, fieldelem);
+         }
+       else if (is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem))
+                || TYPE_FN_FIELD_CONSTRUCTOR (fn, fieldelem))
+         {
+           /* FIXME drow/2007-09-23: We could do this using the name of
+              the method and the name of the class instead of dealing
+              with the mangled name.  We don't have a convenient function
+              to strip off both leading scope qualifiers and trailing
+              template arguments yet.  */
+           if (is_copy_constructor_type (type, fieldtype))
              {
-               struct type *arg_target_type;
-
-               arg_target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
-               if (class_types_same_p (arg_target_type, type))
-                 return 1;
+               /* There may be more than one cctors.  E.g.: one that
+                  take a const parameter and another that takes a
+                  non-const parameter.  Such as:
+
+                  class K {
+                    K (const K &k)...
+                    K (K &k)...
+                  };
+
+                  It is sufficient for the type to be non-trivial
+                  even only one of the cctors is explicit.
+                  Therefore, update the cctor_def value in the
+                  implicit -> explicit direction, not backwards.  */
+
+               if (is_implicit_def (cctor_def))
+                 cctor_def = get_def_style (fn, fieldelem);
+             }
+           else if (is_move_constructor_type (type, fieldtype))
+             {
+               /* Again, there may be multiple move ctors.  Update the
+                  mctor_def value if we found an explicit def and the
+                  existing one is not explicit.  Otherwise retain the
+                  existing value.  */
+               if (is_implicit_def (mctor_def))
+                 mctor_def = get_def_style (fn, fieldelem);
              }
          }
       }
 
+  bool cctor_implicitly_deleted
+    = (mctor_def != DOES_NOT_EXIST_IN_SOURCE
+       && cctor_def == DOES_NOT_EXIST_IN_SOURCE);
+
+  bool cctor_explicitly_deleted = (cctor_def == DELETED);
+
+  if (cctor_implicitly_deleted || cctor_explicitly_deleted)
+    info.copy_constructible = false;
+
+  if (dtor_def == DELETED)
+    info.destructible = false;
+
+  info.trivially_destructible = is_implicit_def (dtor_def);
+
+  info.trivially_copy_constructible
+    = (is_implicit_def (cctor_def)
+       && !is_dynamic);
+
+  info.trivially_copyable
+    = (info.trivially_copy_constructible
+       && info.trivially_destructible
+       && !is_user_provided_def (mctor_def));
+
   /* Even if all the constructors and destructors were artificial, one
      of them may have invoked a non-artificial constructor or
      destructor in a base class.  If any base class needs to be passed
@@ -1318,11 +1500,38 @@ 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 type *field_type = TYPE_FIELD_TYPE (type, fieldnum);
+
+       /* For arrays, make the decision based on the element type.  */
+       if (TYPE_CODE (field_type) == TYPE_CODE_ARRAY)
+         field_type = check_typedef (TYPE_TARGET_TYPE (field_type));
+
+       struct language_pass_by_ref_info field_info
+         = gnuv3_pass_by_reference (field_type);
+
+       if (!field_info.copy_constructible)
+         info.copy_constructible = false;
+       if (!field_info.destructible)
+         info.destructible = false;
+       if (!field_info.trivially_copyable)
+         info.trivially_copyable = false;
+       if (!field_info.trivially_copy_constructible)
+         info.trivially_copy_constructible = false;
+       if (!field_info.trivially_destructible)
+         info.trivially_destructible = false;
+      }
 
-  return 0;
+  /* Consistency check.  */
+  if (has_cc_attr && info.trivially_copyable != is_pass_by_value)
+    {
+      /* DWARF CC attribute is not the same as the inferred value;
+        use the DWARF attribute.  */
+      info.trivially_copyable = is_pass_by_value;
+    }
+
+  return info;
 }
 
 static void
@@ -1359,8 +1568,9 @@ init_gnuv3_ops (void)
   gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
 }
 
+void _initialize_gnu_v3_abi ();
 void
-_initialize_gnu_v3_abi (void)
+_initialize_gnu_v3_abi ()
 {
   init_gnuv3_ops ();