diff --git a/dtool/src/cppparser/cppExtensionType.cxx b/dtool/src/cppparser/cppExtensionType.cxx index 8a0676883d..eba135eb64 100644 --- a/dtool/src/cppparser/cppExtensionType.cxx +++ b/dtool/src/cppparser/cppExtensionType.cxx @@ -131,6 +131,14 @@ is_copy_constructible() const { return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); } +/** + * Returns true if the type is copy-assignable. + */ +bool CPPExtensionType:: +is_copy_assignable() const { + return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); +} + /** * */ diff --git a/dtool/src/cppparser/cppExtensionType.h b/dtool/src/cppparser/cppExtensionType.h index 7f7bf15abf..dca9cf8cb3 100644 --- a/dtool/src/cppparser/cppExtensionType.h +++ b/dtool/src/cppparser/cppExtensionType.h @@ -52,6 +52,7 @@ public: virtual bool is_constructible(const CPPType *type) const; virtual bool is_default_constructible() const; virtual bool is_copy_constructible() const; + virtual bool is_copy_assignable() const; virtual CPPDeclaration *substitute_decl(SubstDecl &subst, CPPScope *current_scope, diff --git a/dtool/src/cppparser/cppFunctionType.h b/dtool/src/cppparser/cppFunctionType.h index a5a66976b0..b6bdff7ac6 100644 --- a/dtool/src/cppparser/cppFunctionType.h +++ b/dtool/src/cppparser/cppFunctionType.h @@ -43,6 +43,8 @@ public: F_volatile_method = 0x4000, F_lvalue_method = 0x8000, F_rvalue_method = 0x10000, + F_copy_assignment_operator = 0x20000, + F_move_assignment_operator = 0x40000, }; CPPFunctionType(CPPType *return_type, CPPParameterList *parameters, diff --git a/dtool/src/cppparser/cppInstance.cxx b/dtool/src/cppparser/cppInstance.cxx index 86768af511..0bfdcabde1 100644 --- a/dtool/src/cppparser/cppInstance.cxx +++ b/dtool/src/cppparser/cppInstance.cxx @@ -328,8 +328,8 @@ get_fully_scoped_name() const { /** * If this is a function type instance, checks whether the function name - * matches the class name (or ~name), and if so, flags it as a constructor (or - * destructor). + * matches the class name (or ~name), and if so, flags it as a constructor, + * destructor or assignment operator */ void CPPInstance:: check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) { @@ -344,13 +344,16 @@ check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) { string class_name = scope->get_local_name(); if (!method_name.empty() && !class_name.empty()) { - if (method_name == class_name) { + // Check either a constructor or assignment operator. + if (method_name == class_name || method_name == "operator =") { CPPType *void_type = CPPType::new_type (new CPPSimpleType(CPPSimpleType::T_void)); - int flags = func->_flags | CPPFunctionType::F_constructor; + int flags = func->_flags; + if (method_name == class_name) { + flags |= CPPFunctionType::F_constructor; + } - // Check if it might be a copy or move constructor. CPPParameterList *params = func->_parameters; if (params->_parameters.size() == 1 && !params->_includes_ellipsis) { CPPType *param_type = params->_parameters[0]->_type; @@ -360,10 +363,18 @@ check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) { param_type = ref_type->_pointing_at->remove_cv(); if (class_name == param_type->get_simple_name()) { - if (ref_type->_value_category == CPPReferenceType::VC_rvalue) { - flags |= CPPFunctionType::F_move_constructor; + if (flags & CPPFunctionType::F_constructor) { + if (ref_type->_value_category == CPPReferenceType::VC_rvalue) { + flags |= CPPFunctionType::F_move_constructor; + } else { + flags |= CPPFunctionType::F_copy_constructor; + } } else { - flags |= CPPFunctionType::F_copy_constructor; + if (ref_type->_value_category == CPPReferenceType::VC_rvalue) { + flags |= CPPFunctionType::F_move_assignment_operator; + } else { + flags |= CPPFunctionType::F_copy_assignment_operator; + } } } } diff --git a/dtool/src/cppparser/cppPointerType.cxx b/dtool/src/cppparser/cppPointerType.cxx index 6fac65a6b1..4ae396e22d 100644 --- a/dtool/src/cppparser/cppPointerType.cxx +++ b/dtool/src/cppparser/cppPointerType.cxx @@ -177,6 +177,14 @@ is_copy_constructible() const { return true; } +/** + * Returns true if the type is copy-assignable. + */ +bool CPPPointerType:: +is_copy_assignable() const { + return true; +} + /** * This is a little more forgiving than is_equal(): it returns true if the * types appear to be referring to the same thing, even if they may have diff --git a/dtool/src/cppparser/cppPointerType.h b/dtool/src/cppparser/cppPointerType.h index 41aed4876b..3fce00b2f5 100644 --- a/dtool/src/cppparser/cppPointerType.h +++ b/dtool/src/cppparser/cppPointerType.h @@ -41,6 +41,7 @@ public: virtual bool is_constructible(const CPPType *other) const; virtual bool is_default_constructible() const; virtual bool is_copy_constructible() const; + virtual bool is_copy_assignable() const; virtual bool is_equivalent(const CPPType &other) const; virtual void output(ostream &out, int indent_level, CPPScope *scope, diff --git a/dtool/src/cppparser/cppSimpleType.cxx b/dtool/src/cppparser/cppSimpleType.cxx index 82d7735bdc..8107e7ee24 100644 --- a/dtool/src/cppparser/cppSimpleType.cxx +++ b/dtool/src/cppparser/cppSimpleType.cxx @@ -103,6 +103,14 @@ is_copy_constructible() const { return (_type != T_void); } +/** + * Returns true if the type is copy-assignable. + */ +bool CPPSimpleType:: +is_copy_assignable() const { + return (_type != T_void); +} + /** * Returns true if the type is destructible. */ diff --git a/dtool/src/cppparser/cppSimpleType.h b/dtool/src/cppparser/cppSimpleType.h index 8adb254a1b..850353e9eb 100644 --- a/dtool/src/cppparser/cppSimpleType.h +++ b/dtool/src/cppparser/cppSimpleType.h @@ -75,6 +75,7 @@ public: virtual bool is_constructible(const CPPType *type) const; virtual bool is_default_constructible() const; virtual bool is_copy_constructible() const; + virtual bool is_copy_assignable() const; virtual bool is_destructible() const; virtual bool is_parameter_expr() const; diff --git a/dtool/src/cppparser/cppStructType.cxx b/dtool/src/cppparser/cppStructType.cxx index afb03dd463..fda8feaa2b 100644 --- a/dtool/src/cppparser/cppStructType.cxx +++ b/dtool/src/cppparser/cppStructType.cxx @@ -435,6 +435,17 @@ is_copy_constructible() const { return is_copy_constructible(V_public); } +/** + * Returns true if the type is copy-assignable. + */ +bool CPPStructType:: +is_copy_assignable() const { + if (is_abstract()) { + return false; + } + return is_copy_assignable(V_public); +} + /** * Returns true if the type is destructible. */ @@ -606,6 +617,97 @@ is_move_constructible(CPPVisibility min_vis) const { return is_copy_constructible(min_vis); } +/** + * Returns true if the type is copy-assignable, without checking whether the + * class is abstract. + */ +bool CPPStructType:: +is_copy_assignable(CPPVisibility min_vis) const { + CPPInstance *assignment_operator = get_copy_assignment_operator(); + if (assignment_operator != (CPPInstance *)NULL) { + // It has a copy assignment operator. + if (assignment_operator->_vis > min_vis) { + // Inaccessible copy assignment operator. + return false; + } + + if (assignment_operator->_storage_class & CPPInstance::SC_deleted) { + // Deleted copy assignment operator. + return false; + } + + // NB: if it's defaulted, it may still be deleted. + if ((assignment_operator->_storage_class & CPPInstance::SC_defaulted) == 0) { + return true; + } + } + + // Implicit copy assignment operator. Check if the implicit or defaulted + // copy assignment operator is deleted. + if (!assignment_operator && (get_move_constructor() || get_move_assignment_operator())) { + // It's not explicitly defaulted, and there is a move constructor or move + // assignment operator, so the implicitly-declared one is deleted. + return false; + } + + Derivation::const_iterator di; + for (di = _derivation.begin(); di != _derivation.end(); ++di) { + CPPStructType *base = (*di)._base->as_struct_type(); + if (base != NULL) { + if (!base->is_copy_assignable(V_protected)) { + return false; + } + } + } + + // Make sure all members are assignable. + CPPScope::Variables::const_iterator vi; + for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { + CPPInstance *instance = (*vi).second; + assert(instance != NULL); + + if (instance->_storage_class & CPPInstance::SC_static) { + // Static members don't count. + continue; + } + + if (!instance->_type->is_copy_assignable()) { + // Const or reference member, can't do it. + return false; + } + } + + return true; +} + +/** + * Returns true if the type is move-assignable. + */ +bool CPPStructType:: +is_move_assignable(CPPVisibility min_vis) const { + CPPInstance *assignment_operator = get_move_assignment_operator(); + if (assignment_operator != (CPPInstance *)NULL) { + // It has a user-declared move assignment_operator. + if (assignment_operator->_vis > min_vis) { + // Inaccessible move assignment_operator. + return false; + } + + if (assignment_operator->_storage_class & CPPInstance::SC_deleted) { + // It is deleted. + return false; + } + + if (is_abstract()) { + return false; + } + + return true; + } + + return is_copy_assignable(min_vis); +} + /** * Returns true if the type is destructible. */ @@ -886,6 +988,80 @@ get_move_constructor() const { return (CPPInstance *)NULL; } +/** + * Returns the assignment operator defined for the struct type, if any, or + * NULL if no assignment operator is found. + */ +CPPFunctionGroup *CPPStructType:: +get_assignment_operator() const { + // Just look for the function with the name "operator =" + CPPScope::Functions::const_iterator fi; + fi = _scope->_functions.find("operator ="); + if (fi != _scope->_functions.end()) { + return fi->second; + } else { + return (CPPFunctionGroup *)NULL; + } +} + +/** + * Returns the copy assignment operator defined for the struct type, or NULL + * if no user-declared copy assignment operator exists. + */ +CPPInstance *CPPStructType:: +get_copy_assignment_operator() const { + CPPFunctionGroup *fgroup = get_assignment_operator(); + if (fgroup == (CPPFunctionGroup *)NULL) { + return (CPPInstance *)NULL; + } + + CPPFunctionGroup::Instances::const_iterator ii; + for (ii = fgroup->_instances.begin(); + ii != fgroup->_instances.end(); + ++ii) { + CPPInstance *inst = (*ii); + assert(inst->_type != (CPPType *)NULL); + + CPPFunctionType *ftype = inst->_type->as_function_type(); + assert(ftype != (CPPFunctionType *)NULL); + + if ((ftype->_flags & CPPFunctionType::F_copy_assignment_operator) != 0) { + return inst; + } + } + + return (CPPInstance *)NULL; +} + +/** + * Returns the move assignment operator defined for the struct type, or NULL + * if no user-declared move assignment operator exists. + */ +CPPInstance *CPPStructType:: +get_move_assignment_operator() const { + CPPFunctionGroup *fgroup = get_assignment_operator(); + if (fgroup == (CPPFunctionGroup *)NULL) { + return (CPPInstance *)NULL; + } + + CPPFunctionGroup::Instances::const_iterator ii; + for (ii = fgroup->_instances.begin(); + ii != fgroup->_instances.end(); + ++ii) { + CPPInstance *inst = (*ii); + assert(inst->_type != (CPPType *)NULL); + + CPPFunctionType *ftype = inst->_type->as_function_type(); + assert(ftype != (CPPFunctionType *)NULL); + + if ((ftype->_flags & CPPFunctionType::F_move_assignment_operator) != 0) { + return inst; + } + } + + return (CPPInstance *)NULL; +} + /** * Returns the destructor defined for the struct type, if any, or NULL if no * user-declared destructor is found. diff --git a/dtool/src/cppparser/cppStructType.h b/dtool/src/cppparser/cppStructType.h index 585c7476b2..9da8777a6c 100644 --- a/dtool/src/cppparser/cppStructType.h +++ b/dtool/src/cppparser/cppStructType.h @@ -56,10 +56,13 @@ public: virtual bool is_constructible(const CPPType *arg_type) const; virtual bool is_default_constructible() const; virtual bool is_copy_constructible() const; + virtual bool is_copy_assignable() const; virtual bool is_destructible() const; bool is_default_constructible(CPPVisibility min_vis) const; bool is_copy_constructible(CPPVisibility min_vis) const; - bool is_move_constructible(CPPVisibility min_vis) const; + bool is_move_constructible(CPPVisibility min_vis = V_public) const; + bool is_copy_assignable(CPPVisibility min_vis) const; + bool is_move_assignable(CPPVisibility min_vis = V_public) const; bool is_destructible(CPPVisibility min_vis) const; virtual bool is_convertible_to(const CPPType *other) const; @@ -69,6 +72,9 @@ public: CPPInstance *get_default_constructor() const; CPPInstance *get_copy_constructor() const; CPPInstance *get_move_constructor() const; + CPPFunctionGroup *get_assignment_operator() const; + CPPInstance *get_copy_assignment_operator() const; + CPPInstance *get_move_assignment_operator() const; CPPInstance *get_destructor() const; virtual CPPDeclaration * diff --git a/dtool/src/cppparser/cppType.cxx b/dtool/src/cppparser/cppType.cxx index 801c571add..af3f511da4 100644 --- a/dtool/src/cppparser/cppType.cxx +++ b/dtool/src/cppparser/cppType.cxx @@ -110,6 +110,14 @@ is_copy_constructible() const { return false; } +/** + * Returns true if the type is copy-assignable. + */ +bool CPPType:: +is_copy_assignable() const { + return false; +} + /** * Returns true if the type is destructible. */ diff --git a/dtool/src/cppparser/cppType.h b/dtool/src/cppparser/cppType.h index c709c475d6..a312f45d33 100644 --- a/dtool/src/cppparser/cppType.h +++ b/dtool/src/cppparser/cppType.h @@ -51,6 +51,7 @@ public: virtual bool is_constructible(const CPPType *type) const; virtual bool is_default_constructible() const; virtual bool is_copy_constructible() const; + virtual bool is_copy_assignable() const; virtual bool is_destructible() const; virtual bool is_parameter_expr() const; diff --git a/dtool/src/cppparser/cppTypedefType.cxx b/dtool/src/cppparser/cppTypedefType.cxx index 61c569760e..d965d5db48 100644 --- a/dtool/src/cppparser/cppTypedefType.cxx +++ b/dtool/src/cppparser/cppTypedefType.cxx @@ -205,6 +205,14 @@ is_copy_constructible() const { return _type->is_copy_constructible(); } +/** + * Returns true if the type is copy-assignable. + */ +bool CPPTypedefType:: +is_copy_assignable() const { + return _type->is_copy_assignable(); +} + /** * Returns true if the type is destructible. */ diff --git a/dtool/src/cppparser/cppTypedefType.h b/dtool/src/cppparser/cppTypedefType.h index 280033738d..04a9b05995 100644 --- a/dtool/src/cppparser/cppTypedefType.h +++ b/dtool/src/cppparser/cppTypedefType.h @@ -48,6 +48,7 @@ public: virtual bool is_constructible(const CPPType *type) const; virtual bool is_default_constructible() const; virtual bool is_copy_constructible() const; + virtual bool is_copy_assignable() const; virtual bool is_destructible() const; virtual bool is_fully_specified() const; diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 575e6fc776..174afca658 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -855,31 +855,13 @@ write_prototypes(ostream &out_code, ostream *out_h) { << " return ((bool (*)(PyObject *, PT(" << class_name << ") &))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced);\n" << "}\n"; } - - } else if (TypeManager::is_trivial(type)) { + } else { out_code << "inline static " << class_name << " *Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " &coerced) {\n" << " nassertr(Dtool_Ptr_" << safe_name << " != NULL, NULL);\n" << " nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != NULL, NULL);\n" << " return ((" << class_name << " *(*)(PyObject *, " << class_name << " &))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced);\n" << "}\n"; - - } else { - out_code - << "inline static bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, " << class_name << " const *&coerced, bool &manage) {\n" - << " nassertr(Dtool_Ptr_" << safe_name << " != NULL, false);\n" - << " nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce != NULL, false);\n" - << " return ((bool (*)(PyObject *, " << class_name << " const *&, bool&))Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce)(args, coerced, manage);\n" - << "}\n"; - - if (has_coerce > 1) { - out_code - << "inline static bool Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " *&coerced, bool &manage) {\n" - << " nassertr(Dtool_Ptr_" << safe_name << " != NULL, false);\n" - << " nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != NULL, false);\n" - << " return ((bool (*)(PyObject *, " << class_name << " *&, bool&))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced, manage);\n" - << "}\n"; - } } } out_code << "#else\n"; @@ -888,20 +870,12 @@ write_prototypes(ostream &out_code, ostream *out_h) { if (has_coerce > 0) { if (TypeManager::is_reference_count(type)) { - assert(!type->is_trivial()); out_code << "extern bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, CPT(" << class_name << ") &coerced);\n"; if (has_coerce > 1) { out_code << "extern bool Dtool_Coerce_" << safe_name << "(PyObject *args, PT(" << class_name << ") &coerced);\n"; } - - } else if (TypeManager::is_trivial(type)) { - out_code << "extern " << class_name << " *Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " &coerced);\n"; - } else { - out_code << "extern bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, " << class_name << " const *&coerced, bool &manage);\n"; - if (has_coerce > 1) { - out_code << "extern bool Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " *&coerced, bool &manage);\n"; - } + out_code << "extern " << class_name << " *Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " &coerced);\n"; } } out_code << "#endif\n"; @@ -1062,7 +1036,7 @@ write_class_details(ostream &out, Object *obj) { int has_coerce = has_coerce_constructor(cpptype->as_struct_type()); if (has_coerce > 0) { write_coerce_constructor(out, obj, true); - if (has_coerce > 1 && !TypeManager::is_trivial(obj->_itype._cpptype)) { + if (has_coerce > 1 && TypeManager::is_reference_count(obj->_itype._cpptype)) { write_coerce_constructor(out, obj, false); } } @@ -1182,20 +1156,12 @@ write_class_declarations(ostream &out, ostream *out_h, Object *obj) { int has_coerce = has_coerce_constructor(type->as_struct_type()); if (has_coerce > 0) { if (TypeManager::is_reference_count(type)) { - assert(!type->is_trivial()); out << "bool Dtool_ConstCoerce_" << class_name << "(PyObject *args, CPT(" << c_class_name << ") &coerced);\n"; if (has_coerce > 1) { out << "bool Dtool_Coerce_" << class_name << "(PyObject *args, PT(" << c_class_name << ") &coerced);\n"; } - - } else if (TypeManager::is_trivial(type)) { - out << "" << c_class_name << " *Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " &coerced);\n"; - } else { - out << "bool Dtool_ConstCoerce_" << class_name << "(PyObject *args, " << c_class_name << " const *&coerced, bool &manage);\n"; - if (has_coerce > 1) { - out << "bool Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " *&coerced, bool &manage);\n"; - } + out << "" << c_class_name << " *Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " &coerced);\n"; } } @@ -3046,8 +3012,7 @@ write_module_class(ostream &out, Object *obj) { int has_coerce = has_coerce_constructor(obj->_itype._cpptype->as_struct_type()); if (has_coerce > 0) { - if (TypeManager::is_reference_count(obj->_itype._cpptype) || - !TypeManager::is_trivial(obj->_itype._cpptype)) { + if (TypeManager::is_reference_count(obj->_itype._cpptype)) { out << " (CoerceFunction)Dtool_ConstCoerce_" << ClassName << ",\n"; if (has_coerce > 1) { out << " (CoerceFunction)Dtool_Coerce_" << ClassName << ",\n"; @@ -3920,7 +3885,7 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) { } return_flags |= RF_err_false; - } else if (TypeManager::is_trivial(obj->_itype._cpptype)) { + } else { out << cClassName << " *Dtool_Coerce_" << ClassName << "(PyObject *args, " << cClassName << " &coerced) {\n"; out << " " << cClassName << " *local_this;\n"; @@ -3934,26 +3899,6 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) { out << " return local_this;\n"; return_flags |= RF_err_null; - - } else { - if (is_const) { - out << "bool Dtool_ConstCoerce_" << ClassName << "(PyObject *args, " << cClassName << " const *&coerced, bool &manage) {\n"; - } else { - out << "bool Dtool_Coerce_" << ClassName << "(PyObject *args, " << cClassName << " *&coerced, bool &manage) {\n"; - } - - out << " DTOOL_Call_ExtractThisPointerForType(args, &Dtool_" << ClassName << ", (void**)&coerced);\n"; - out << " if (coerced != NULL) {\n"; - if (!is_const) { - out << " if (!((Dtool_PyInstDef *)args)->_is_const) {\n"; - out << " // A non-const instance is required, which this is.\n"; - out << " return true;\n"; - out << " }\n"; - } else { - out << " return true;\n"; - } - - return_flags |= RF_err_false; } out << " }\n\n"; @@ -5498,8 +5443,8 @@ write_function_instance(ostream &out, FunctionRemap *remap, // actual PointerTo. This eliminates an unref()ref() pair. pexpr_string = "MOVE(" + param_name + "_this)"; - } else if (TypeManager::is_trivial(obj_type)) { - // This is a trivial type, such as TypeHandle or LVecBase4. + } else { + // This is a move-assignable type, such as TypeHandle or LVecBase4. obj_type->output_instance(extra_convert, param_name + "_local", &parser); extra_convert << ";\n"; @@ -5522,29 +5467,6 @@ write_function_instance(ostream &out, FunctionRemap *remap, coerce_call = "(" + param_name + "_this != NULL)"; pexpr_string = param_name + "_this"; - - } else { - // This is a bit less elegant: we use a bool to store whether we're - // supposed to clean up the reference afterward. - type->output_instance(extra_convert, param_name + "_this", &parser); - extra_convert - << default_expr << ";\n" - << "bool " << param_name << "_manage = false;\n"; - - if (TypeManager::is_const_pointer_or_ref(orig_type)) { - coerce_call = "Dtool_ConstCoerce_" + make_safe_name(class_name) + - "(" + param_name + ", " + param_name + "_this, " + param_name + "_manage)"; - } else { - coerce_call = "Dtool_Coerce_" + make_safe_name(class_name) + - "(" + param_name + ", " + param_name + "_this, " + param_name + "_manage)"; - } - - extra_cleanup - << "if (" << param_name << "_manage) {\n" - << " delete " << param_name << "_this;\n" - << "}\n"; - - pexpr_string = param_name + "_this"; } if (report_errors) { @@ -5848,7 +5770,7 @@ write_function_instance(ostream &out, FunctionRemap *remap, manage_return = remap->_return_value_needs_management; return_expr = "return_value"; - } else if ((return_flags & RF_coerced) != 0 && TypeManager::is_trivial(remap->_cpptype)) { + } else if ((return_flags & RF_coerced) != 0 && !TypeManager::is_reference_count(remap->_cpptype)) { // Another special case is the coerce constructor for a trivial type. We // don't want to invoke "operator new" unnecessarily. if (is_constructor && remap->_extension) { @@ -6152,13 +6074,8 @@ write_function_instance(ostream &out, FunctionRemap *remap, indent(out, indent_level) << "coerced = MOVE(" << return_expr << ");\n"; indent(out, indent_level) << "return true;\n"; - } else if (TypeManager::is_trivial(remap->_cpptype)) { - indent(out, indent_level) << "return &coerced;\n"; - } else { - indent(out, indent_level) << "coerced = " << return_expr << ";\n"; - indent(out, indent_level) << "manage = true;\n"; - indent(out, indent_level) << "return true;\n"; + indent(out, indent_level) << "return &coerced;\n"; } } else if (return_flags & RF_raise_keyerror) { @@ -7357,6 +7274,14 @@ has_coerce_constructor(CPPStructType *type) { return 0; } + // It is convenient to set default-constructability and move-assignability + // as requirement for non-reference-counted objects, since it simplifies the + // implementation and it holds for all classes we need it for. + if (!TypeManager::is_reference_count(type) && + (!type->is_default_constructible() || !type->is_move_assignable())) { + return 0; + } + CPPScope *scope = type->get_scope(); if (scope == NULL) { return 0; diff --git a/dtool/src/interrogate/typeManager.cxx b/dtool/src/interrogate/typeManager.cxx index 995f677cc6..1485c785ca 100644 --- a/dtool/src/interrogate/typeManager.cxx +++ b/dtool/src/interrogate/typeManager.cxx @@ -2517,55 +2517,3 @@ is_local(CPPType *source_type) { return false; */ } - -/** - * Returns true if the type is trivial (or trivial enough for our purposes). - */ -bool TypeManager:: -is_trivial(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_trivial(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return false; - - case CPPDeclaration::ST_pointer: - return true; - - case CPPDeclaration::ST_simple: - return true; - - case CPPDeclaration::ST_typedef: - return is_trivial(source_type->as_typedef_type()->_type); - - default: - if (source_type->is_trivial() || is_handle(source_type)) { - return true; - } else { - // This is a bit of a hack. is_trivial() returns false for types that - // have an empty constructor (since we can't use =default yet). For the - // other classes, it's just convenient to consider them trivial even if - // they aren't, since they are simple enough. - string name = source_type->get_simple_name(); - return (name == "ButtonHandle" || name == "DatagramIterator" || - name == "BitMask" || name == "Filename" || name == "pixel" || - name == "NodePath" || name == "LoaderOptions" || - name == "PointerToArray" || name == "ConstPointerToArray" || - name == "PStatThread" || - (name.size() >= 6 && name.substr(0, 6) == "LPlane") || - (name.size() > 6 && name.substr(0, 6) == "LPoint") || - (name.size() > 7 && name.substr(0, 7) == "LVector") || - (name.size() > 7 && name.substr(0, 7) == "LMatrix") || - (name.size() > 8 && name.substr(0, 8) == "LVecBase") || - (name.size() >= 9 && name.substr(0, 9) == "LParabola") || - (name.size() >= 9 && name.substr(0, 9) == "LRotation") || - (name.size() >= 11 && name.substr(0, 11) == "LQuaternion") || - (name.size() >= 12 && name.substr(0, 12) == "LOrientation") || - (name.size() > 16 && name.substr(0, 16) == "UnalignedLMatrix") || - (name.size() > 17 && name.substr(0, 17) == "UnalignedLVecBase")); - } - } - - return false; -} diff --git a/dtool/src/interrogate/typeManager.h b/dtool/src/interrogate/typeManager.h index 97b4bd8158..65f192edf7 100644 --- a/dtool/src/interrogate/typeManager.h +++ b/dtool/src/interrogate/typeManager.h @@ -149,7 +149,6 @@ public: static bool is_exported(CPPType *type); static bool is_local(CPPType *type); - static bool is_trivial(CPPType *type); }; #endif diff --git a/dtool/src/parser-inc/iostream b/dtool/src/parser-inc/iostream index 6ba0763c44..170d1d03f9 100644 --- a/dtool/src/parser-inc/iostream +++ b/dtool/src/parser-inc/iostream @@ -88,6 +88,9 @@ __published: streampos tellp(); void seekp(streampos pos); void seekp(streamoff off, ios_base::seekdir dir); + +protected: + ostream(ostream &&); }; class istream : virtual public ios { __published: @@ -97,12 +100,18 @@ __published: streampos tellg(); void seekg(streampos pos); void seekg(streamoff off, ios_base::seekdir dir); + +protected: + istream(istream &&); }; class iostream : public istream, public ostream { __published: iostream(const iostream&) = delete; void flush(); + +protected: + iostream(iostream &&); }; class ofstream : public ostream { diff --git a/panda/src/express/pointerToArray.h b/panda/src/express/pointerToArray.h index b4458f17b8..e3dcc2f110 100644 --- a/panda/src/express/pointerToArray.h +++ b/panda/src/express/pointerToArray.h @@ -247,6 +247,8 @@ private: template class ConstPointerToArray : public PointerToArrayBase { public: + INLINE ConstPointerToArray(TypeHandle type_handle = get_type_handle(Element)); + // By hiding this template from interrogate, we would improve compile-time // speed and memory utilization. However, we do want to export a minimal // subset of this class. So we define just the exportable interface here. @@ -287,7 +289,6 @@ PUBLISHED: typedef TYPENAME pvector::difference_type difference_type; typedef TYPENAME pvector::size_type size_type; - INLINE ConstPointerToArray(TypeHandle type_handle = get_type_handle(Element)); INLINE ConstPointerToArray(const Element *begin, const Element *end, TypeHandle type_handle = get_type_handle(Element)); INLINE ConstPointerToArray(const PointerToArray ©); INLINE ConstPointerToArray(const ConstPointerToArray ©); diff --git a/panda/src/pgraph/nodePathCollection.I b/panda/src/pgraph/nodePathCollection.I index 6c7b5df2d6..1ea730f4ab 100644 --- a/panda/src/pgraph/nodePathCollection.I +++ b/panda/src/pgraph/nodePathCollection.I @@ -11,13 +11,6 @@ * @date 2002-03-06 */ -/** - * - */ -INLINE NodePathCollection:: -~NodePathCollection() { -} - /** * Appends the other list onto the end of this one. */ diff --git a/panda/src/pgraph/nodePathCollection.cxx b/panda/src/pgraph/nodePathCollection.cxx index a2310b9e99..40efb80192 100644 --- a/panda/src/pgraph/nodePathCollection.cxx +++ b/panda/src/pgraph/nodePathCollection.cxx @@ -19,30 +19,6 @@ #include "colorAttrib.h" #include "indent.h" -/** - * - */ -NodePathCollection:: -NodePathCollection() { -} - -/** - * - */ -NodePathCollection:: -NodePathCollection(const NodePathCollection ©) : - _node_paths(copy._node_paths) -{ -} - -/** - * - */ -void NodePathCollection:: -operator = (const NodePathCollection ©) { - _node_paths = copy._node_paths; -} - /** * Adds a new NodePath to the collection. */ diff --git a/panda/src/pgraph/nodePathCollection.h b/panda/src/pgraph/nodePathCollection.h index 1d1ba9bd1f..9eb0c1ce90 100644 --- a/panda/src/pgraph/nodePathCollection.h +++ b/panda/src/pgraph/nodePathCollection.h @@ -25,10 +25,7 @@ */ class EXPCL_PANDA_PGRAPH NodePathCollection { PUBLISHED: - NodePathCollection(); - NodePathCollection(const NodePathCollection ©); - void operator = (const NodePathCollection ©); - INLINE ~NodePathCollection(); + NodePathCollection() DEFAULT_CTOR; #ifdef HAVE_PYTHON EXTENSION(NodePathCollection(PyObject *self, PyObject *sequence));