diff options
author | David Faust <david.faust@oracle.com> | 2022-04-27 11:27:49 -0700 |
---|---|---|
committer | David Faust <david.faust@oracle.com> | 2022-04-27 12:00:18 -0700 |
commit | fd51331270ed0318144cb0031b21ef710218e2fe (patch) | |
tree | d3adea79abd3b1793c79a2474f037cc328736af9 | |
parent | 9a9bb44058a8406b41bb1ab3110e08a897772bb0 (diff) | |
download | gcc-fd51331270ed0318144cb0031b21ef710218e2fe.zip gcc-fd51331270ed0318144cb0031b21ef710218e2fe.tar.gz gcc-fd51331270ed0318144cb0031b21ef710218e2fe.tar.bz2 |
Support align and packed repr on structs
-rw-r--r-- | gcc/rust/backend/rust-compile-type.cc | 20 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-base.cc | 67 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-base.h | 3 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-stmt.h | 16 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-toplevel.h | 16 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.cc | 3 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.h | 28 | ||||
-rw-r--r-- | gcc/rust/util/rust-attributes.cc | 1 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/struct_align1.rs | 19 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/struct_align2.rs | 18 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/struct_pack1.rs | 19 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/struct_pack2.rs | 18 |
12 files changed, 223 insertions, 5 deletions
diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 07b95c7..16029ba 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -280,6 +280,26 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) type_record = ctx->get_backend ()->union_type (enum_fields); } + // Handle repr options + // TODO: "packed" should only narrow type alignment and "align" should only + // widen it. Do we need to check and enforce this here, or is it taken care of + // later on in the gcc middle-end? + TyTy::ADTType::ReprOptions repr = type.get_repr_options (); + if (repr.pack) + { + TYPE_PACKED (type_record); + if (repr.pack > 1) + { + SET_TYPE_ALIGN (type_record, repr.pack * 8); + TYPE_USER_ALIGN (type_record) = 1; + } + } + else if (repr.align) + { + SET_TYPE_ALIGN (type_record, repr.align * 8); + TYPE_USER_ALIGN (type_record) = 1; + } + std::string named_struct_str = type.get_ident ().path.get () + type.subst_as_string (); tree named_struct diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 4e8fa26..2a47c58 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -260,5 +260,72 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, return infered; } +TyTy::ADTType::ReprOptions +TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus) +{ + TyTy::ADTType::ReprOptions repr; + repr.pack = 0; + repr.align = 0; + + for (const auto &attr : attrs) + { + bool is_repr = attr.get_path ().as_string ().compare ("repr") == 0; + if (is_repr) + { + const AST::AttrInput &input = attr.get_attr_input (); + bool is_token_tree = input.get_attr_input_type () + == AST::AttrInput::AttrInputType::TOKEN_TREE; + rust_assert (is_token_tree); + const auto &option = static_cast<const AST::DelimTokenTree &> (input); + AST::AttrInputMetaItemContainer *meta_items + = option.parse_to_meta_item (); + + const std::string inline_option + = meta_items->get_items ().at (0)->as_string (); + + // TODO: it would probably be better to make the MetaItems more aware + // of constructs with nesting like #[repr(packed(2))] rather than + // manually parsing the string "packed(2)" here. + + size_t oparen = inline_option.find ('(', 0); + bool is_pack = false, is_align = false; + unsigned char value = 1; + + if (oparen == std::string::npos) + { + is_pack = inline_option.compare ("packed") == 0; + is_align = inline_option.compare ("align") == 0; + } + + else + { + std::string rep = inline_option.substr (0, oparen); + is_pack = rep.compare ("packed") == 0; + is_align = rep.compare ("align") == 0; + + size_t cparen = inline_option.find (')', oparen); + if (cparen == std::string::npos) + { + rust_error_at (locus, "malformed attribute"); + } + + std::string value_str = inline_option.substr (oparen, cparen); + value = strtoul (value_str.c_str () + 1, NULL, 10); + } + + if (is_pack) + repr.pack = value; + else if (is_align) + repr.align = value; + + // Multiple repr options must be specified with e.g. #[repr(C, + // packed(2))]. + break; + } + } + + return repr; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index 159f826..f7a1bd4 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -58,6 +58,9 @@ protected: TyTy::BaseType *resolve_literal (const Analysis::NodeMapping &mappings, HIR::Literal &literal, Location locus); + TyTy::ADTType::ReprOptions parse_repr_options (const AST::AttrVec &attrs, + Location locus); + Analysis::Mappings *mappings; Resolver *resolver; TypeCheckContext *context; diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index 4298771..2f14966 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -185,12 +185,18 @@ public: TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields))); + // Process #[repr(...)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + TyTy::BaseType *type = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), mappings->get_next_hir_id (), struct_decl.get_identifier (), ident, TyTy::ADTType::ADTKind::TUPLE_STRUCT, - std::move (variants), std::move (substitutions)); + std::move (variants), std::move (substitutions), + repr); context->insert_type (struct_decl.get_mappings (), type); infered = type; @@ -311,12 +317,18 @@ public: TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields))); + // Process #[repr(...)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + TyTy::BaseType *type = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), mappings->get_next_hir_id (), struct_decl.get_identifier (), ident, TyTy::ADTType::ADTKind::STRUCT_STRUCT, - std::move (variants), std::move (substitutions)); + std::move (variants), std::move (substitutions), + repr); context->insert_type (struct_decl.get_mappings (), type); infered = type; diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h index 40aaa87..eaa8d59 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h +++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h @@ -118,12 +118,18 @@ public: TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields))); + // Process #[repr(X)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + TyTy::BaseType *type = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), mappings->get_next_hir_id (), struct_decl.get_identifier (), ident, TyTy::ADTType::ADTKind::TUPLE_STRUCT, - std::move (variants), std::move (substitutions)); + std::move (variants), std::move (substitutions), + repr); context->insert_type (struct_decl.get_mappings (), type); } @@ -196,12 +202,18 @@ public: TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields))); + // Process #[repr(X)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + TyTy::BaseType *type = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), mappings->get_next_hir_id (), struct_decl.get_identifier (), ident, TyTy::ADTType::ADTKind::STRUCT_STRUCT, - std::move (variants), std::move (substitutions)); + std::move (variants), std::move (substitutions), + repr); context->insert_type (struct_decl.get_mappings (), type); } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 847ca88..4090304 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -960,7 +960,8 @@ ADTType::clone () const return new ADTType (get_ref (), get_ty_ref (), identifier, ident, get_adt_kind (), cloned_variants, clone_substs (), - used_arguments, get_combined_refs ()); + get_repr_options (), used_arguments, + get_combined_refs ()); } static bool diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 271ce2c..e2f1aa4 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -1254,6 +1254,20 @@ public: ENUM }; + // Representation options, specified via attributes e.g. #[repr(packed)] + struct ReprOptions + { + // bool is_c; + // bool is_transparent; + //... + + // For align and pack: 0 = unspecified. Nonzero = byte alignment. + // It is an error for both to be nonzero, this should be caught when + // parsing the #[repr] attribute. + unsigned char align = 0; + unsigned char pack = 0; + }; + ADTType (HirId ref, std::string identifier, RustIdent ident, ADTKind adt_kind, std::vector<VariantDef *> variants, std::vector<SubstitutionParamMapping> subst_refs, @@ -1276,7 +1290,20 @@ public: identifier (identifier), variants (variants), adt_kind (adt_kind) {} + ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident, + ADTKind adt_kind, std::vector<VariantDef *> variants, + std::vector<SubstitutionParamMapping> subst_refs, ReprOptions repr, + SubstitutionArgumentMappings generic_arguments + = SubstitutionArgumentMappings::error (), + std::set<HirId> refs = std::set<HirId> ()) + : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), + SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)), + identifier (identifier), variants (variants), adt_kind (adt_kind), + repr (repr) + {} + ADTKind get_adt_kind () const { return adt_kind; } + ReprOptions get_repr_options () const { return repr; } bool is_struct_struct () const { return adt_kind == STRUCT_STRUCT; } bool is_tuple_struct () const { return adt_kind == TUPLE_STRUCT; } @@ -1385,6 +1412,7 @@ private: std::string identifier; std::vector<VariantDef *> variants; ADTType::ADTKind adt_kind; + ReprOptions repr; }; class FnType : public BaseType, public SubstitutionRef diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index 77f884e..c36d462 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -33,6 +33,7 @@ static const BuiltinAttrDefinition __definitions[] = { {"lang", HIR_LOWERING}, {"link_section", CODE_GENERATION}, {"no_mangle", CODE_GENERATION}, + {"repr", CODE_GENERATION}, }; BuiltinAttributeMappings * diff --git a/gcc/testsuite/rust/compile/struct_align1.rs b/gcc/testsuite/rust/compile/struct_align1.rs new file mode 100644 index 0000000..22eb6bc --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_align1.rs @@ -0,0 +1,19 @@ +#[repr(align(8))] +struct Foo { + x: i16, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + y: i8, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + z: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +#[repr(align(8))] +struct Bar(i8, i32); + +fn main () { + let f = Foo { x: 5, y: 2, z: 13 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = Bar (7, 262); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/struct_align2.rs b/gcc/testsuite/rust/compile/struct_align2.rs new file mode 100644 index 0000000..ac49064 --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_align2.rs @@ -0,0 +1,18 @@ + +fn main () { + + #[repr(align(8))] + struct Baz { + x: u16, + y: u32, + }; + + #[repr(align(4))] + struct Qux (u8, i16); + + let b = Baz { x: 5, y: 1984 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c = Qux (1, 2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/struct_pack1.rs b/gcc/testsuite/rust/compile/struct_pack1.rs new file mode 100644 index 0000000..eb9d879 --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_pack1.rs @@ -0,0 +1,19 @@ +#[repr(packed(2))] +struct Foo { + x: i16, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + y: i8, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + z: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +#[repr(packed)] +struct Bar(i8, i32); + +fn main () { + let f = Foo { x: 5, y: 2, z: 13 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = Bar (7, 262); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/struct_pack2.rs b/gcc/testsuite/rust/compile/struct_pack2.rs new file mode 100644 index 0000000..e5f74c2 --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_pack2.rs @@ -0,0 +1,18 @@ + +fn main () { + + #[repr(packed(2))] + struct Baz { + x: u16, + y: u32, + }; + + #[repr(packed)] + struct Qux (u8, i16); + + let b = Baz { x: 5, y: 1984 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c = Qux (1, 2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} |