Skip to content
/ bond Public
forked from microsoft/bond

Commit

Permalink
Make reflection.h types C++20 compatible.
Browse files Browse the repository at this point in the history
As of C++20, it is malformed to have an unnamed class used in typedef with a
base class. In the generated reflection code for a struct, we were using the
following construct to create a reflectable entry for each field in a
struct.

```
struct var {
    typedef struct /* no name */ : ::bond::reflection::FieldTemplate<...> {} field_name;
}
```

Now, instead of using an unnamed class, we generate a named class and refer
to that:

```
struct var {
    typedef struct field_name_type : ::bond::reflection::FieldTemplate<...> {} field_name;
}
```

Since the "field_name_type" struct now has a name in the `var` struct, it
may conflict with user-defined field names in the struct. (E.g., if there is
another field with the name "field_name_type") To avoid this problem, we
ensure that the generated type name is unique. This means that the name of
the type may change as fields are add/removed from structs. Only the member
for each field in the `var` struct is part of the interface, not the name of
the type providing its implementation, so we're free to change the names of
these types now and at any time in the future.

See also, [C++ proposal P1766R1][1], which make the code we had malformed.

Fixes microsoft#1027

[1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1766r1.html
  • Loading branch information
BertusGreeff authored Apr 29, 2020
1 parent 802438e commit f1cb707
Show file tree
Hide file tree
Showing 98 changed files with 2,630 additions and 1,482 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ different versioning scheme, following the Haskell community's
for MSVC 2013, which is no longer a supported compiler.
* Fixed MSVC warning for deprecation of `std::result_of_t` in `/std:c++17`.
([Issue #1007](https://github.com/microsoft/bond/issues/1007))
* Fixed MSVC warning C5208: unnamed class used in typedef name cannot
declare members other than non-static data members, member enumerations,
or member classes. ([Issue
#1027](https://github.com/microsoft/bond/issues/1027))

### C# ###

Expand Down
21 changes: 15 additions & 6 deletions compiler/src/Language/Bond/Codegen/Cpp/Reflection_h.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ reflection_h export_attribute cpp file imports declarations = ("_reflection.h",
#{CPP.closeNamespace cpp}
|])
where
idl = MappingContext idlTypeMapping [] [] []
idl = MappingContext idlTypeMapping [] [] []

-- C++ type
cppType = getTypeName cpp
Expand All @@ -51,7 +51,7 @@ reflection_h export_attribute cpp file imports declarations = ("_reflection.h",
#{newlineBeginSep 2 fieldMetadata structFields}

public: struct var
{#{fieldTemplates structFields}};
{#{fieldTemplates (zip structFields uniqueFieldTemplateStructNames)}};

private: typedef boost::mpl::list<> fields0;
#{newlineSep 2 pushField indexedFields}
Expand Down Expand Up @@ -92,7 +92,7 @@ reflection_h export_attribute cpp file imports declarations = ("_reflection.h",
}|]
where
static Field {..} = [lt|(void)s_#{fieldName}_metadata;|]

-- reversed list of field names zipped with indexes
indexedFields :: [(String, Int)]
indexedFields = zipWith ((,) . fieldName) (reverse structFields) [0..]
Expand All @@ -106,16 +106,25 @@ reflection_h export_attribute cpp file imports declarations = ("_reflection.h",
fieldMetadata Field {..} =
[lt|private: #{export_attr}static const ::bond::Metadata s_#{fieldName}_metadata;|]

fieldTemplates = F.foldMap $ \ f@Field {..} -> [lt|
-- fieldTemplateReservedNames are names used in ::bond::reflection::FieldTemplate<>
fieldTemplateReservedNames = ["FieldTemplate", "struct_type", "field_pointer", "field_type", "value_type", "field_modifier", "metadata", "field", "id", "GetVariable"]

fieldNames = map (\f -> fieldName f) structFields

fieldTemplateStructReservedNames = fieldTemplateReservedNames ++ fieldNames

uniqueFieldTemplateStructNames = uniqueNames (map (\n -> n ++ "_type") fieldNames) fieldTemplateStructReservedNames

fieldTemplates = F.foldMap $ \ (f@Field {..}, sn) -> [lt|
// #{fieldName}
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct #{sn} : ::bond::reflection::FieldTemplate<
#{fieldOrdinal},
#{CPP.modifierTag f},
#{className},
#{cppType fieldType},
&#{className}::#{fieldName},
&s_#{fieldName}_metadata
> {} #{fieldName};
> {} #{fieldName};
|]


Expand Down
1 change: 1 addition & 0 deletions compiler/tests/TestMain.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ tests = testGroup "Compiler tests"
, verifyCppCodegen "aliases"
, verifyCppCodegen "alias_key"
, verifyCppCodegen "maybe_blob"
, verifyCppCodegen "metadata_edge_cases"
, verifyCodegen
[ "c++"
, "--enum-header"
Expand Down
8 changes: 4 additions & 4 deletions compiler/tests/generated/alias_key_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ namespace test
public: struct var
{
// m
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct m_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
foo,
std::map<std::string, int32_t>,
&foo::m,
&s_m_metadata
> {} m;
> {} m;

// s
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct s_type : ::bond::reflection::FieldTemplate<
1,
::bond::reflection::optional_field_modifier,
foo,
std::set<int32_t>,
&foo::s,
&s_s_metadata
> {} s;
> {} s;
};

private: typedef boost::mpl::list<> fields0;
Expand Down
56 changes: 28 additions & 28 deletions compiler/tests/generated/alias_with_allocator_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,124 +31,124 @@ namespace test
public: struct var
{
// l
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct l_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
foo,
std::list<bool, typename std::allocator_traits<arena>::template rebind_alloc<bool> >,
&foo::l,
&s_l_metadata
> {} l;
> {} l;

// v
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct v_type : ::bond::reflection::FieldTemplate<
1,
::bond::reflection::optional_field_modifier,
foo,
std::vector<bool, typename std::allocator_traits<arena>::template rebind_alloc<bool> >,
&foo::v,
&s_v_metadata
> {} v;
> {} v;

// s
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct s_type : ::bond::reflection::FieldTemplate<
2,
::bond::reflection::optional_field_modifier,
foo,
std::set<bool, std::less<bool>, typename std::allocator_traits<arena>::template rebind_alloc<bool> >,
&foo::s,
&s_s_metadata
> {} s;
> {} s;

// m
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct m_type : ::bond::reflection::FieldTemplate<
3,
::bond::reflection::optional_field_modifier,
foo,
std::map<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, bool, std::less<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > >, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, bool> > >,
&foo::m,
&s_m_metadata
> {} m;
> {} m;

// st
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct st_type : ::bond::reflection::FieldTemplate<
4,
::bond::reflection::optional_field_modifier,
foo,
std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >,
&foo::st,
&s_st_metadata
> {} st;
> {} st;

// d
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct d_type : ::bond::reflection::FieldTemplate<
5,
::bond::reflection::optional_field_modifier,
foo,
std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >,
&foo::d,
&s_d_metadata
> {} d;
> {} d;

// l1
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct l1_type : ::bond::reflection::FieldTemplate<
10,
::bond::reflection::optional_field_modifier,
foo,
::bond::maybe<std::list<bool, typename std::allocator_traits<arena>::template rebind_alloc<bool> > >,
&foo::l1,
&s_l1_metadata
> {} l1;
> {} l1;

// v1
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct v1_type : ::bond::reflection::FieldTemplate<
11,
::bond::reflection::optional_field_modifier,
foo,
::bond::maybe<std::vector<bool, typename std::allocator_traits<arena>::template rebind_alloc<bool> > >,
&foo::v1,
&s_v1_metadata
> {} v1;
> {} v1;

// s1
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct s1_type : ::bond::reflection::FieldTemplate<
12,
::bond::reflection::optional_field_modifier,
foo,
::bond::maybe<std::set<bool, std::less<bool>, typename std::allocator_traits<arena>::template rebind_alloc<bool> > >,
&foo::s1,
&s_s1_metadata
> {} s1;
> {} s1;

// m1
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct m1_type : ::bond::reflection::FieldTemplate<
13,
::bond::reflection::optional_field_modifier,
foo,
::bond::maybe<std::map<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, bool, std::less<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > >, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, bool> > > >,
&foo::m1,
&s_m1_metadata
> {} m1;
> {} m1;

// st1
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct st1_type : ::bond::reflection::FieldTemplate<
14,
::bond::reflection::optional_field_modifier,
foo,
::bond::maybe<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > >,
&foo::st1,
&s_st1_metadata
> {} st1;
> {} st1;

// na
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct na_type : ::bond::reflection::FieldTemplate<
15,
::bond::reflection::optional_field_modifier,
foo,
std::set<std::list<std::map<int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > > > >, typename std::allocator_traits<arena>::template rebind_alloc<std::map<int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > > > > > >, std::less<std::list<std::map<int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > > > >, typename std::allocator_traits<arena>::template rebind_alloc<std::map<int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > > > > > > >, typename std::allocator_traits<arena>::template rebind_alloc<std::list<std::map<int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > > > >, typename std::allocator_traits<arena>::template rebind_alloc<std::map<int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const int32_t, std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > > > > > > > >,
&foo::na,
&s_na_metadata
> {} na;
> {} na;
};

private: typedef boost::mpl::list<> fields0;
Expand Down Expand Up @@ -192,24 +192,24 @@ namespace test
public: struct var
{
// f
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct f_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
withFoo,
::test::foo,
&withFoo::f,
&s_f_metadata
> {} f;
> {} f;

// f1
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct f1_type : ::bond::reflection::FieldTemplate<
1,
::bond::reflection::optional_field_modifier,
withFoo,
::test::foo,
&withFoo::f1,
&s_f1_metadata
> {} f1;
> {} f1;
};

private: typedef boost::mpl::list<> fields0;
Expand Down
8 changes: 4 additions & 4 deletions compiler/tests/generated/aliases_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ namespace tests
public: struct var
{
// aa
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct aa_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
Foo<T>,
std::vector<std::vector<T> >,
&Foo<T>::aa,
&s_aa_metadata
> {} aa;
> {} aa;
};

private: typedef boost::mpl::list<> fields0;
Expand Down Expand Up @@ -73,14 +73,14 @@ namespace tests
public: struct var
{
// aWrappedEnum
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct aWrappedEnum_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
WrappingAnEnum,
::tests::EnumToWrap,
&WrappingAnEnum::aWrappedEnum,
&s_aWrappedEnum_metadata
> {} aWrappedEnum;
> {} aWrappedEnum;
};

private: typedef boost::mpl::list<> fields0;
Expand Down
8 changes: 4 additions & 4 deletions compiler/tests/generated/alloc_ctors/alias_key_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ namespace test
public: struct var
{
// m
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct m_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
foo,
std::map<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, int32_t, std::less<std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> > >, typename std::allocator_traits<arena>::template rebind_alloc<std::pair<const std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >, int32_t> > >,
&foo::m,
&s_m_metadata
> {} m;
> {} m;

// s
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct s_type : ::bond::reflection::FieldTemplate<
1,
::bond::reflection::optional_field_modifier,
foo,
std::set<int32_t, std::less<int32_t>, typename std::allocator_traits<arena>::template rebind_alloc<int32_t> >,
&foo::s,
&s_s_metadata
> {} s;
> {} s;
};

private: typedef boost::mpl::list<> fields0;
Expand Down
8 changes: 4 additions & 4 deletions compiler/tests/generated/alloc_ctors/aliases_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ namespace tests
public: struct var
{
// aa
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct aa_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
Foo<T>,
std::vector<std::vector<T, typename std::allocator_traits<arena>::template rebind_alloc<T> >, typename std::allocator_traits<arena>::template rebind_alloc<std::vector<T, typename std::allocator_traits<arena>::template rebind_alloc<T> > > >,
&Foo<T>::aa,
&s_aa_metadata
> {} aa;
> {} aa;
};

private: typedef boost::mpl::list<> fields0;
Expand Down Expand Up @@ -73,14 +73,14 @@ namespace tests
public: struct var
{
// aWrappedEnum
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct aWrappedEnum_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
WrappingAnEnum,
::tests::EnumToWrap,
&WrappingAnEnum::aWrappedEnum,
&s_aWrappedEnum_metadata
> {} aWrappedEnum;
> {} aWrappedEnum;
};

private: typedef boost::mpl::list<> fields0;
Expand Down
4 changes: 2 additions & 2 deletions compiler/tests/generated/alloc_ctors/attributes_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ namespace tests
public: struct var
{
// f
typedef struct : ::bond::reflection::FieldTemplate<
typedef struct f_type : ::bond::reflection::FieldTemplate<
0,
::bond::reflection::optional_field_modifier,
Foo,
std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<arena>::template rebind_alloc<char> >,
&Foo::f,
&s_f_metadata
> {} f;
> {} f;
};

private: typedef boost::mpl::list<> fields0;
Expand Down
Loading

0 comments on commit f1cb707

Please sign in to comment.