aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Faust <david.faust@oracle.com>2022-04-27 11:27:49 -0700
committerDavid Faust <david.faust@oracle.com>2022-04-27 12:00:18 -0700
commitfd51331270ed0318144cb0031b21ef710218e2fe (patch)
treed3adea79abd3b1793c79a2474f037cc328736af9
parent9a9bb44058a8406b41bb1ab3110e08a897772bb0 (diff)
downloadgcc-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.cc20
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-base.cc67
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-base.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.h16
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-toplevel.h16
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc3
-rw-r--r--gcc/rust/typecheck/rust-tyty.h28
-rw-r--r--gcc/rust/util/rust-attributes.cc1
-rw-r--r--gcc/testsuite/rust/compile/struct_align1.rs19
-rw-r--r--gcc/testsuite/rust/compile/struct_align2.rs18
-rw-r--r--gcc/testsuite/rust/compile/struct_pack1.rs19
-rw-r--r--gcc/testsuite/rust/compile/struct_pack2.rs18
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 }
+}