rust-qt / ritual

Use C++ libraries from Rust
Apache License 2.0
1.24k stars 49 forks source link

Failure in all type caption strategies for methods with multiple return values #22

Closed alexchandel closed 8 years ago

alexchandel commented 8 years ago

The panic message is:

values dump: [CppMethodWithFfiSignature { cpp_method: CppMethod { name: "_nil", class_membership: Some(CppMethodClassMembership { class_type: CppTypeClassBase { name: "CORBA::_omni_AbstractBaseObjref", template_arguments: None }, kind: Regular, is_virtual: false, is_pure_virtual: false, is_const: false, is_static: true, visibility: Public, is_signal: false }), operator: None, return_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::Object", template_arguments: None }), indirection: Ptr, is_const: false }, arguments: [], arguments_before_omitting: None, allows_variadic_arguments: false, include_file: "CORBA_AbstractBase.h", origin_location: None, template_arguments: None, declaration_code: None, inherited_from: Some(CppMethodInheritedFrom { doc_id: "CORBA::Object::_nil", declaration_code: Some("static _ptr_type _nil ( )"), short_text: "static CORBA::Object* CORBA::Object::_nil()", class_type: CppTypeClassBase { name: "CORBA::Object", template_arguments: None } }) }, allocation_place: NotApplicable, c_signature: CppFfiFunctionSignature { arguments: [], return_type: CppFfiType { original_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::Object", template_arguments: None }), indirection: Ptr, is_const: false }, ffi_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::Object", template_arguments: None }), indirection: Ptr, is_const: false }, conversion: NoChange } } }, CppMethodWithFfiSignature { cpp_method: CppMethod { name: "_nil", class_membership: Some(CppMethodClassMembership { class_type: CppTypeClassBase { name: "CORBA::_omni_AbstractBaseObjref", template_arguments: None }, kind: Regular, is_virtual: false, is_pure_virtual: false, is_const: false, is_static: true, visibility: Public, is_signal: false }), operator: None, return_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: Ptr, is_const: false }, arguments: [], arguments_before_omitting: None, allows_variadic_arguments: false, include_file: "CORBA_AbstractBase.h", origin_location: None, template_arguments: None, declaration_code: None, inherited_from: Some(CppMethodInheritedFrom { doc_id: "CORBA::AbstractBase::_nil", declaration_code: Some("static _ptr_type _nil ( )"), short_text: "static CORBA::AbstractBase* CORBA::AbstractBase::_nil()", class_type: CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None } }) }, allocation_place: NotApplicable, c_signature: CppFfiFunctionSignature { arguments: [], return_type: CppFfiType { original_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: Ptr, is_const: false }, ffi_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: Ptr, is_const: false }, conversion: NoChange } } }]

All type caption strategies have failed! Involved functions:
  static CORBA::Object* CORBA::_omni_AbstractBaseObjref::_nil()
  static CORBA::AbstractBase* CORBA::_omni_AbstractBaseObjref::_nil()
thread 'main' panicked at 'all type caption strategies have failed', src/cpp_ffi_generator.rs:212

I'm guessing the failure is due to the overloaded return type. This should be captionable if the argument types are.

Riateche commented 8 years ago

Overloading by return type does not exist in C++. It's not possible to declare such methods in C++, so this is some kind of logic error, and the generator panics. In this case, the methods are added from two base classes of _omni_AbstractBaseObjref. None of them should be added because of ambiguity. The inheritance algorithm should be corrected for this case. Quick way to fix this error is to blacklist the method in the lib spec:

"cpp": {
    ...,
    "ffi_methods_blacklist": [
      "CORBA::_omni_AbstractBaseObjref::_nil"
    ]
}
alexchandel commented 8 years ago

I also see it for:

All type caption strategies have failed! Involved functions:
  [constructor] void CORBA::BAD_QOS::BAD_QOS(unsigned int minor_ = ?, CORBA::CompletionStatus completed_ = ?)
  [constructor] void CORBA::BAD_QOS::BAD_QOS(const CORBA::BAD_QOS& ex = ?)
  [constructor] void CORBA::BAD_QOS::BAD_QOS(unsigned int minor_ = ?)
  [constructor] void CORBA::BAD_QOS::BAD_QOS()
  [constructor] void CORBA::BAD_QOS::BAD_QOS()

Is that also a multiple-inheritance issue?

Edit: also CORBA::INV_POLICY::INV_POLICY, CORBA::BAD_TYPECODE::BAD_TYPECODE, CORBA::PERSIST_STORE::PERSIST_STORE, CORBA::CODESET_INCOMPATIBLE::CODESET_INCOMPATIBLE, ..., I went ahead and blacklisted everything in omniORB4/userexception.h

alexchandel commented 8 years ago

This looks like different bug:

All type caption strategies have failed! Involved functions:
  pure virtual CosNaming::_objref_NamingContext* POA_CosNaming::NamingContextExt::bind_new_context(const CosNaming::Name& n)
  pure virtual CosNaming::_objref_NamingContext* POA_CosNaming::NamingContextExt::bind_new_context(const CosNaming::Name& n)

Exact same names & signatures.

Edit: nvm, this is due to multiple inheritance, but the inheritance is virtual so only one copy of methods/fields should arrive at the bottom.

alexchandel commented 8 years ago

@Riateche Part of this may be due to a failure to detect virtual inheritance.

alexchandel commented 8 years ago

A new, similar looking error, as of 6297e42824d2da8b92a94579a304f5c6028cc472:

Generating C++ FFI methods for header: omnithread.h
values dump: [CppMethodWithFfiSignature { cpp_method: CppMethod { name: "omni_thread", ... (extremely long line)

All type caption strategies have failed! Involved functions:
  [constructor] void omni_thread::omni_thread(void (*FN_PTR)(void*) fn, void* arg = ?, omni_thread::priority_t pri = ?)
  [constructor] void omni_thread::omni_thread(void* (*FN_PTR)(void*) fn, void* arg = ?, omni_thread::priority_t pri = ?)
  [constructor] void omni_thread::omni_thread(void (*FN_PTR)(void*) fn, void* arg = ?)
  [constructor] void omni_thread::omni_thread(void (*FN_PTR)(void*) fn)
  [constructor] void omni_thread::omni_thread(void* (*FN_PTR)(void*) fn, void* arg = ?)
  [constructor] void omni_thread::omni_thread(void* (*FN_PTR)(void*) fn)
Riateche commented 8 years ago

Most of the errors are caused by diamond inheritance. BAD_QOS error was caused by clang's strange incorrect parse results. omni_thread error happened because I didn't expect to have two functions with almost the same signatures but different function pointer types. I've fixed all of them. It now compiles correctly on my system.

Here is the spec.json I used:

{
  "cpp": {
    "name": "omniORB4",
    "extra_libs": ["omnithread", "COS4", "COSDynamic4", "omniCodeSets4", "omniConnectionMgmt4", "omniDynamic4", "omniZIOP4", "omniZIOPDynamic4"],
    "include_file": "omniORB4/CORBA.h",
    "include_dirs": ["../../../omni_orb/omniORB-4.2.1/include"],
    "target_include_dirs": ["../../../omni_orb/omniORB-4.2.1/include"],
    "lib_dirs": ["../../../omni_orb/omniORB-4.2.1/lib"],
    "name_blacklist": ["CORBA::Object::_get_implementation"],
    "ffi_methods_blacklist": [
      "_CORBA_Unbounded_Sequence<DynamicAny::NameDynAnyPair>::operator<<=",
      "_CORBA_Unbounded_Sequence<DynamicAny::NameDynAnyPair>::operator>>=",
      "DynamicAny::NameDynAnyPairSeq::operator<<=",
      "DynamicAny::NameDynAnyPairSeq::operator>>=",
      "_CORBA_Unbounded_Sequence<DynamicAny::NameValuePair>::operator<<=",
      "_CORBA_Unbounded_Sequence<DynamicAny::NameValuePair>::operator>>=",
      "DynamicAny::NameValuePairSeq::operator<<=",
      "DynamicAny::NameValuePairSeq::operator>>=",
      "POA_PortableServer::AdapterActivator::_do_get_interface",
      "_CORBA_ObjRef_INOUT_arg<DynamicAny::DynAny, DynamicAny::DynAny_Helper>::_CORBA_ObjRef_INOUT_arg",
      "_CORBA_ObjRef_INOUT_arg<PortableServer::POA, PortableServer::POA_Helper>::_CORBA_ObjRef_INOUT_arg",

      "DynamicAny::DynValueCommon::_duplicate",
      "DynamicAny::DynValueCommon::_narrow",
      "CORBA::Principal::_duplicate",
      "CORBA::Principal::_nil",
      "PortableServer::AdapterActivator_Helper::duplicate",
      "CORBA::Any::PR_equivalent",
      "CORBA::TypeCode::NP_abstract_interface_tc",
      "CORBA::TypeCode::NP_local_interface_tc",
      "CORBA::TypeCode::NP_native_tc",
      "IOP::dumpComponent",
      "CORBA::ORB::create_abstract_interface_tc",
      "CORBA::ORB::create_local_interface_tc",
      "CORBA::LocalObject_Member& CORBA::LocalObject_Member::operator=(const CORBA::LocalObject_Element& p)",
      "[constructor] void CORBA::LocalObject_var::LocalObject_var(const CORBA::LocalObject_Member& p)",
      "[constructor] void CORBA::LocalObject_var::LocalObject_var(const CORBA::LocalObject_Element& p)",
      "CORBA::LocalObject_var& CORBA::LocalObject_var::operator=(const CORBA::LocalObject_Member& p)",
      "CORBA::LocalObject_var& CORBA::LocalObject_var::operator=(const CORBA::LocalObject_Element& p)",
      "bool CORBA::is_nil(CORBA::Principal* arg1)",
      "bool CORBA::is_nil(CORBA::DomainManager* p)",
      "void CORBA::release(CORBA::Principal* arg1)",
      "void CORBA::release(CORBA::DomainManager* arg1)",
      "_CORBA_null_string_ptr",
      "CORBA::DomainManager::_duplicate",
      "CORBA::DomainManager::_nil",
      "CORBA::DomainManager::get_domain_policy",
      "void operator<<=(bool& a, cdrStream& s)",
      "void operator<<=(char& a, cdrStream& s)",
      "void operator<<=(unsigned char& a, cdrStream& s)",
      "void operator>>=(bool a, cdrStream& s)",
      "void operator>>=(char a, cdrStream& s)",
      "void operator>>=(unsigned char a, cdrStream& s)"
    ]
  },
  "rust": {

  }
}

There are quite a lot of blacklisted methods. It's just not possible to infer that these methods are not actually available based on the headers. I intend to implement automatic detection of these situations in the future.

I don't know what's the usual workflow for working with this library. I'd say it's better to create wrapper for the library itself, and then create wrappers for the classes generated from IDL using the first crate as a dependency. That way, multiple projects can use the same crate, which can be convenient. But if it's typical to only have one IDL file per system, it's possible to generate a single crate.