diff --git a/hilti/runtime/include/type-info.h b/hilti/runtime/include/type-info.h index c5d43c727..45a48e634 100644 --- a/hilti/runtime/include/type-info.h +++ b/hilti/runtime/include/type-info.h @@ -900,9 +900,9 @@ struct Field { * @param offset offset of the field in number bytes inside the struct * @param accessor function returning a pointer to a fields value */ - Field(const char* name, const TypeInfo* type, std::ptrdiff_t offset, bool internal, + Field(const char* name, const TypeInfo* type, std::ptrdiff_t offset, bool internal, bool anonymous, Accessor accessor = accessor_default) - : name(name), type(type), offset(offset), accessor(accessor), internal(internal) {} + : name(name), type(type), offset(offset), accessor(accessor), internal(internal), anonymous(anonymous) {} /** Default accessor function suitable for non-optional fields. */ static const void* accessor_default(const Value& v) { return v.pointer(); } @@ -921,6 +921,7 @@ struct Field { }; } + bool isAnonymous() const { return anonymous; } bool isInternal() const { return internal; } const std::string name; /**< ID of the field */ @@ -935,6 +936,7 @@ struct Field { const std::ptrdiff_t offset; const Accessor accessor; const bool internal; + const bool anonymous; }; }; // namespace struct_ diff --git a/hilti/runtime/src/tests/type-info.cc b/hilti/runtime/src/tests/type-info.cc index dc943d6cf..f93ed7584 100644 --- a/hilti/runtime/src/tests/type-info.cc +++ b/hilti/runtime/src/tests/type-info.cc @@ -54,14 +54,14 @@ namespace { const hilti::rt::TypeInfo __ti_Test_X = {"Test::X", "Test::X", new hilti::rt::type_info::Struct(std::vector( - {hilti::rt::type_info::struct_::Field{"i", &hilti::rt::type_info::int32, offsetof(Test::X, i), false}, - hilti::rt::type_info::struct_::Field{"s", &hilti::rt::type_info::string, offsetof(Test::X, s), false}, - hilti::rt::type_info::struct_::Field{"y", &type_info::__ti_Test_Y, offsetof(Test::X, y), false}}))}; + {hilti::rt::type_info::struct_::Field{"i", &hilti::rt::type_info::int32, offsetof(Test::X, i), false, false}, + hilti::rt::type_info::struct_::Field{"s", &hilti::rt::type_info::string, offsetof(Test::X, s), false, false}, + hilti::rt::type_info::struct_::Field{"y", &type_info::__ti_Test_Y, offsetof(Test::X, y), false, false}}))}; const hilti::rt::TypeInfo __ti_Test_Y = {"Test::Y", "Test::Y", new hilti::rt::type_info::Struct(std::vector( - {hilti::rt::type_info::struct_::Field{"b", &hilti::rt::type_info::bool_, offsetof(Test::Y, b), false}, - hilti::rt::type_info::struct_::Field{"r", &hilti::rt::type_info::real, offsetof(Test::Y, r), false}}))}; + {hilti::rt::type_info::struct_::Field{"b", &hilti::rt::type_info::bool_, offsetof(Test::Y, b), false, false}, + hilti::rt::type_info::struct_::Field{"r", &hilti::rt::type_info::real, offsetof(Test::Y, r), false, false}}))}; } // namespace } // namespace __hlt::type_info @@ -126,10 +126,10 @@ TEST_CASE("internal fields") { const TypeInfo ti = {"A", "A", new type_info::Struct( - {type_info::struct_::Field{"f1", &type_info::int32, offsetof(A, f1), false}, - type_info::struct_::Field{"f2", &type_info::string, offsetof(A, f2), false}, + {type_info::struct_::Field{"f1", &type_info::int32, offsetof(A, f1), false, false}, + type_info::struct_::Field{"f2", &type_info::string, offsetof(A, f2), false, false}, type_info::struct_::Field{"__internal", &type_info::bool_, offsetof(A, __internal), - true}})}; + true, false}})}; auto sx = StrongReference({42, "foo", true}); auto p = type_info::value::Parent(sx); @@ -146,4 +146,23 @@ TEST_CASE("internal fields") { CHECK_EQ(s->iterate(v, true).size(), 3U); } +TEST_CASE("anonymous fields") { + struct A { + std::string f1; + }; + + const TypeInfo ti = {"A", "A", + new type_info::Struct( + {type_info::struct_::Field{"f1", &type_info::int32, offsetof(A, f1), false, true}})}; + + auto sx = StrongReference({"foo"}); + auto p = type_info::value::Parent(sx); + auto v = type_info::Value(&*sx, &ti, p); + + const auto s = type_info::value::auxType(v); + + CHECK_EQ(s->fields().size(), 1U); + CHECK(s->fields()[0].get().isAnonymous()); +} + TEST_SUITE_END(); diff --git a/hilti/toolchain/include/ast/declarations/field.h b/hilti/toolchain/include/ast/declarations/field.h index cbd218c05..efe360551 100644 --- a/hilti/toolchain/include/ast/declarations/field.h +++ b/hilti/toolchain/include/ast/declarations/field.h @@ -69,6 +69,7 @@ class Field : public DeclarationBase { return {}; } + auto isAnonymous() const { return AttributeSet::find(attributes(), "&anonymous").has_value(); } auto isInternal() const { return AttributeSet::find(attributes(), "&internal").has_value(); } auto isOptional() const { return AttributeSet::find(attributes(), "&optional").has_value(); } auto isStatic() const { return AttributeSet::find(attributes(), "&static").has_value(); } diff --git a/hilti/toolchain/src/compiler/codegen/types.cc b/hilti/toolchain/src/compiler/codegen/types.cc index 2acd0c961..45fcf74af 100644 --- a/hilti/toolchain/src/compiler/codegen/types.cc +++ b/hilti/toolchain/src/compiler/codegen/types.cc @@ -901,8 +901,8 @@ struct VisitorTypeInfoDynamic : hilti::visitor::PreOrdertypeInfo(f.type()), cxx_type_id, cxx::ID(f.id()), f.isInternal(), + fields.push_back(fmt("::hilti::rt::type_info::struct_::Field{ \"%s\", %s, offsetof(%s, %s), %s, %s%s }", + cxx::ID(f.id()), cg->typeInfo(f.type()), cxx_type_id, cxx::ID(f.id()), f.isInternal(), f.isAnonymous(), accessor)); } diff --git a/spicy/toolchain/bin/spicy-dump/printer-text.cc b/spicy/toolchain/bin/spicy-dump/printer-text.cc index df674c40d..9ad33c5e8 100644 --- a/spicy/toolchain/bin/spicy-dump/printer-text.cc +++ b/spicy/toolchain/bin/spicy-dump/printer-text.cc @@ -136,7 +136,11 @@ void TextPrinter::print(const type_info::Value& v) { if ( y ) { out() << '\n'; outputIndent(); - out() << f.name << ": "; + + if ( ! f.isAnonymous() ) + out() << f.name; + + out() << ": "; print(y); const auto& offset = offsets && offsets->size() > index ? offsets->at(index) : std::nullopt; diff --git a/spicy/toolchain/src/compiler/codegen/unit-builder.cc b/spicy/toolchain/src/compiler/codegen/unit-builder.cc index 581ceadad..a10d51d11 100644 --- a/spicy/toolchain/src/compiler/codegen/unit-builder.cc +++ b/spicy/toolchain/src/compiler/codegen/unit-builder.cc @@ -41,6 +41,9 @@ struct FieldBuilder : public hilti::visitor::PreOrder { if ( auto x = AttributeSet::find(f.attributes(), "&default") ) attrs = AttributeSet::add(attrs, *x); + if ( f.isAnonymous() ) + attrs = AttributeSet::add(attrs, Attribute("&anonymous")); + if ( (f.isAnonymous() || f.isSkip() || f.parseType().isA()) && ! f.itemType().isA() ) // This field will never make it into the C++ struct. We still diff --git a/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt b/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt index a7d5959eb..cd125f0d2 100644 --- a/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt +++ b/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt @@ -83,7 +83,7 @@ type C = struct { method tuple, int<64>, iterator, optional> __parse_foo_C_stage2(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error); } &on-heap; public type D = struct { - value_ref anon &optional &no-emit; + value_ref anon &optional &anonymous &no-emit; optional> __begin &internal &needed-by-feature="uses_random_access"; optional> __position &internal &needed-by-feature="uses_random_access"; optional> __position_update &internal &needed-by-feature="uses_random_access"; diff --git a/tests/Baseline/spicy.optimization.unused-functions/opt.hlt b/tests/Baseline/spicy.optimization.unused-functions/opt.hlt index 336f69cf6..bcbd14f0c 100644 --- a/tests/Baseline/spicy.optimization.unused-functions/opt.hlt +++ b/tests/Baseline/spicy.optimization.unused-functions/opt.hlt @@ -19,7 +19,7 @@ type C = struct { method tuple, int<64>, iterator, optional> __parse_foo_C_stage2(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error); } &on-heap; public type D = struct { - value_ref anon &optional &no-emit; + value_ref anon &optional &anonymous &no-emit; spicy_rt::Parser __parser &static &internal &needed-by-feature="supports_filters" &always-emit; optional __error &always-emit &internal; method tuple, int<64>, iterator, optional> __parse_stage1(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error); diff --git a/tests/Baseline/spicy.optimization.unused-types/noopt.hlt b/tests/Baseline/spicy.optimization.unused-types/noopt.hlt index ca0226cbd..3f2b0d3dd 100644 --- a/tests/Baseline/spicy.optimization.unused-types/noopt.hlt +++ b/tests/Baseline/spicy.optimization.unused-types/noopt.hlt @@ -109,7 +109,7 @@ type Priv3 = struct { method tuple, int<64>, iterator, optional> __parse_foo_Priv3_stage2(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error); } &on-heap; type Priv4 = struct { - value_ref anon &optional &no-emit; + value_ref anon &optional &anonymous &no-emit; value_ref x &optional; optional> __begin &internal &needed-by-feature="uses_random_access"; optional> __position &internal &needed-by-feature="uses_random_access"; @@ -190,7 +190,7 @@ type Priv6 = struct { method tuple, int<64>, iterator, optional> __parse_foo_Priv6_stage2(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error); } &on-heap; public type Pub3 = struct { - value_ref anon_2 &optional &no-emit; + value_ref anon_2 &optional &anonymous &no-emit; value_ref x &optional; optional> __begin &internal &needed-by-feature="uses_random_access"; optional> __position &internal &needed-by-feature="uses_random_access"; diff --git a/tests/Baseline/spicy.optimization.unused-types/opt.hlt b/tests/Baseline/spicy.optimization.unused-types/opt.hlt index 022c706f4..6ff14e0aa 100644 --- a/tests/Baseline/spicy.optimization.unused-types/opt.hlt +++ b/tests/Baseline/spicy.optimization.unused-types/opt.hlt @@ -24,7 +24,7 @@ type Priv6 = struct { method tuple, int<64>, iterator, optional> __parse_foo_Priv6_stage2(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error); } &on-heap; public type Pub3 = struct { - value_ref anon_2 &optional &no-emit; + value_ref anon_2 &optional &anonymous &no-emit; value_ref x &optional; spicy_rt::Parser __parser &static &internal &needed-by-feature="supports_filters" &always-emit; optional __error &always-emit &internal; diff --git a/tests/Baseline/spicy.types.bitfield.anonymous-field/output b/tests/Baseline/spicy.types.bitfield.anonymous-field/output index 29e274b01..dc200f22c 100644 --- a/tests/Baseline/spicy.types.bitfield.anonymous-field/output +++ b/tests/Baseline/spicy.types.bitfield.anonymous-field/output @@ -1,2 +1,5 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. 15, 15 +Test::Foo { + : (x: 15, y: 15) +} diff --git a/tests/spicy/types/bitfield/anonymous-field.spicy b/tests/spicy/types/bitfield/anonymous-field.spicy index ef0f8b309..d0b788c32 100644 --- a/tests/spicy/types/bitfield/anonymous-field.spicy +++ b/tests/spicy/types/bitfield/anonymous-field.spicy @@ -1,4 +1,5 @@ # @TEST-EXEC: printf '\377' | spicy-driver %INPUT >output +# @TEST-EXEC: printf '\377' | spicy-dump %INPUT >>output # @TEST-EXEC: btest-diff output module Test;