public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Support align and packed repr on structs
@ 2022-06-08 12:39 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:39 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fd51331270ed0318144cb0031b21ef710218e2fe

commit fd51331270ed0318144cb0031b21ef710218e2fe
Author: David Faust <david.faust@oracle.com>
Date:   Wed Apr 27 11:27:49 2022 -0700

    Support align and packed repr on structs

Diff:
---
 gcc/rust/backend/rust-compile-type.cc             | 20 +++++++
 gcc/rust/typecheck/rust-hir-type-check-base.cc    | 67 +++++++++++++++++++++++
 gcc/rust/typecheck/rust-hir-type-check-base.h     |  3 +
 gcc/rust/typecheck/rust-hir-type-check-stmt.h     | 16 +++++-
 gcc/rust/typecheck/rust-hir-type-check-toplevel.h | 16 +++++-
 gcc/rust/typecheck/rust-tyty.cc                   |  3 +-
 gcc/rust/typecheck/rust-tyty.h                    | 28 ++++++++++
 gcc/rust/util/rust-attributes.cc                  |  1 +
 gcc/testsuite/rust/compile/struct_align1.rs       | 19 +++++++
 gcc/testsuite/rust/compile/struct_align2.rs       | 18 ++++++
 gcc/testsuite/rust/compile/struct_pack1.rs        | 19 +++++++
 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 07b95c78e5a..16029baf5d2 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 4e8fa269ca6..2a47c58664b 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 159f8261c9e..f7a1bd4fa84 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 42987716f4f..2f14966ed66 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 40aaa872d84..eaa8d59d001 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 847ca88900f..4090304dc2b 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 271ce2c386b..e2f1aa49c8b 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 77f884e7fd4..c36d462537d 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 00000000000..22eb6bc80fb
--- /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 00000000000..ac490643a36
--- /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 00000000000..eb9d879c1dc
--- /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 00000000000..e5f74c20bb0
--- /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 }
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:39 [gcc/devel/rust/master] Support align and packed repr on structs Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).