+/* 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 (method_type->num_fields () < 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 (arg_type->code () != 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 < method_type->num_fields (); 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.