Skip to content

[cpp] List in a variant generates invalid function binding #1332

Open
@Lucky1313

Description

@Lucky1313

Given a WIT definition which includes a function returning a variant that includes a list:

package local:[email protected];

interface task {
  variant value {
    a(bool),
    b(list<u8>),
  }
  
  do-thing: func() -> value;
}

world test {
  import task;
}

And generating C++17 bindings using latest master (7f92598):

wit-bingen cpp test.wit

test.cpp:

...snip
extern "C" __attribute__((import_module("local:test/[email protected]")))
__attribute__((import_name("do-thing")))
void localX3AtestX2FtaskX400X2E1X2E0X00do_thing(uint8_t *);
local::test::task::Value local::test::task::DoThing()
{
  uintptr_t ret_area[((3*sizeof(void*))+sizeof(uintptr_t)-1)/sizeof(uintptr_t)];
  uint8_t* ptr0 = (uint8_t*)(&ret_area);
  localX3AtestX2FtaskX400X2E1X2E0X00do_thing(ptr0);
  Value variant2;
  switch ((int32_t) (*((uint8_t*) (ptr0 + 0)))) {
    case 0: { 
      variant2.variants = Value::A{(bool((int32_t) (*((uint8_t*) (ptr0 + sizeof(void*))))))};
    } break;
    case 1: { auto len1 = *((size_t*) (ptr0 + (2*sizeof(void*))));

    variant2.variants = Value::B{wit::vector<uint8_t>((uint8_t*)(*((uint8_t**) (ptr0 + sizeof(void*)))), len1)};
  } break;
}
auto result3 = variant2;
return result3;
}
...snip

The bindings are unable to compile, I think due to the copy constructor for the variant that includes the wit::vector being deleted:

/opt/wasi-sdk/bin/clang++ -std=c++20 -fno-exceptions -Wall -Wextra -Wc++-compat -g --target=wasm32-wasip2 -O2 -I/bindings -c /bindings/test.cpp -o test.o
/bindings/test.cpp:44:6: error: call to implicitly-deleted copy constructor of 'Value'
   44 | auto result3 = variant2;
      |      ^         ~~~~~~~~
/bindings/test_cpp.h:11:22: note: copy constructor of 'Value' is implicitly deleted because field 'variants' has a deleted copy constructor
   11 |   std::variant<A, B> variants;
...snip

If the copy from the variant2 to result3 object is removed, and we return the variant2 object directly, the code compiles successfully.

Generated `test.cpp` file

// Generated by `wit-bindgen` 0.43.0. DO NOT EDIT!

// Ensure that the *_component_type.o object is linked in
#ifdef __wasm32__
extern "C" void __component_type_object_force_link_test(void);
__attribute__((used))
void __component_type_object_force_link_test_public_use_in_this_compilation_unit(void) {
  __component_type_object_force_link_test();
}
#endif
#include "test_cpp.h"
#include <cstdlib> // realloc

extern "C" void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size);

__attribute__((__weak__, __export_name__("cabi_realloc")))
void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) {
  (void) old_size;
  if (new_size == 0) return (void*) align;
  void *ret = realloc(ptr, new_size);
  if (!ret) abort();
  return ret;
}


extern "C" __attribute__((import_module("local:test/[email protected]")))
__attribute__((import_name("do-thing")))
void localX3AtestX2FtaskX400X2E1X2E0X00do_thing(uint8_t *);
local::test::task::Value local::test::task::DoThing()
{
  uintptr_t ret_area[((3*sizeof(void*))+sizeof(uintptr_t)-1)/sizeof(uintptr_t)];
  uint8_t* ptr0 = (uint8_t*)(&ret_area);
  localX3AtestX2FtaskX400X2E1X2E0X00do_thing(ptr0);
  Value variant2;
  switch ((int32_t) (*((uint8_t*) (ptr0 + 0)))) {
    case 0: { 
      variant2.variants = Value::A{(bool((int32_t) (*((uint8_t*) (ptr0 + sizeof(void*))))))};
    } break;
    case 1: { auto len1 = *((size_t*) (ptr0 + (2*sizeof(void*))));

    variant2.variants = Value::B{wit::vector<uint8_t>((uint8_t*)(*((uint8_t**) (ptr0 + sizeof(void*)))), len1)};
  } break;
}
auto result3 = variant2;
return result3;
}

// Component Adapters

Generated `test_cpp.h` file

// Generated by `wit-bindgen` 0.43.0. DO NOT EDIT!
#ifndef __CPP_GUEST_BINDINGS_TEST_H
#define __CPP_GUEST_BINDINGS_TEST_H
#include <cstdint>
#include <utility>
#include <variant>
#include "wit.h"
namespace local {namespace test {namespace task {struct Value {
  struct A { bool value; };
  struct B { wit::vector<uint8_t> value; };
  std::variant<A, B> variants;
};
Value DoThing();
}}}

#endif

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions