@@ -19,7 +19,9 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_ALGORITHM
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
@@ -28,8 +30,13 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "diagnostic.h"
#include "tree-diagnostic.h"
+#include "intl.h"
+#include "make-unique.h"
#include "analyzer/analyzer.h"
#include "analyzer/record-layout.h"
+#include "text-art/table.h"
+#include "text-art/widget.h"
+#include "diagnostic-diagram.h"
#if ENABLE_ANALYZER
@@ -120,6 +127,234 @@ record_layout::maybe_pad_to (bit_offset_t next_offset)
}
}
+class layout_diagram : public text_art::vbox_widget
+{
+public:
+ layout_diagram (const ana::record_layout &layout,
+ text_art::style_manager &sm,
+ const text_art::theme &theme);
+
+private:
+ text_art::table::coord_t bit_to_table_coord (ana::bit_offset_t bit);
+
+ void ensure_table_rows (text_art::style_manager &sm,
+ text_art::table &table,
+ int table_y);
+
+ text_art::styled_string
+ get_string_for_item (const ana::record_layout::item &item,
+ text_art::style_manager &sm);
+
+ std::vector<tree> m_footnote_fields;
+ bool m_has_short_padding;
+};
+
+layout_diagram::layout_diagram (const ana::record_layout &layout,
+ text_art::style_manager &sm,
+ const text_art::theme &theme)
+: m_has_short_padding (false)
+{
+ using namespace text_art;
+
+ table table (table::size_t (34, 2));
+ table.set_cell (table::coord_t (0, 0), styled_string (sm, _("Offsets")));
+ table.set_cell (table::coord_t (1, 0), styled_string (sm, _("Byte")));
+ table.set_cell (table::coord_t (0, 1), styled_string (sm, _("Byte")));
+ for (int octet = 0; octet < 4; octet++)
+ table.set_cell_span (table::rect_t (table::coord_t (2 + (octet * 8), 0),
+ table::size_t (8, 1)),
+ styled_string::from_fmt (sm, nullptr, "%i", octet));
+ table.set_cell (table::coord_t (1, 1), styled_string (sm, _("Bit")));
+ for (int bit = 0; bit < 32; bit++)
+ table.set_cell (table::coord_t (bit + 2, 1),
+ styled_string::from_fmt (sm, nullptr, "%i", bit));
+
+ for (auto &item : layout.m_items)
+ {
+ table::coord_t start_coord
+ = bit_to_table_coord (item.get_start_bit_offset ());
+ table::coord_t max_coord
+ = bit_to_table_coord (item.get_next_bit_offset () - 1);
+ gcc_assert (start_coord.y <= max_coord.y);
+ ensure_table_rows (sm, table, max_coord.y);
+ styled_string content (get_string_for_item (item, sm));
+ if (start_coord.y == max_coord.y)
+ {
+ table.set_cell_span
+ (table::rect_t (start_coord,
+ table::size_t (max_coord.x + 1 - start_coord.x,
+ 1)),
+ std::move (content));
+ }
+ else
+ {
+ /* Item is split between multiple rows. */
+ table::range_t full_rows (start_coord.y, max_coord.y + 1);
+ // Initial row
+ if (start_coord.x > 2)
+ {
+ table.set_cell_span
+ (table::rect_t (start_coord,
+ table::size_t (34 - start_coord.x, 1)),
+ get_string_for_item (item, sm));
+ full_rows.start++;
+ }
+
+ // Final row
+ if (max_coord.x < 33)
+ {
+ table.set_cell_span
+ (table::rect_t (table::coord_t (2, max_coord.y),
+ table::size_t (33 - max_coord.x, 1)),
+ get_string_for_item (item, sm));
+ full_rows.next--;
+ }
+
+ // Middle rows
+ if (full_rows.get_size () > 0)
+ table.set_cell_span
+ (table::rect_t (table::range_t (2, 34),
+ full_rows),
+ std::move (content));
+ }
+ }
+
+ /* Add a child widget for the table. */
+ text_art::canvas canvas (table.to_canvas (theme, sm));
+ add_child (::make_unique <canvas_widget> (std::move (canvas)));
+
+ /* Add text child widgets for any lines with showing footnotes. */
+ if (m_has_short_padding)
+ {
+ styled_string s
+ (styled_string::from_fmt (sm, default_tree_printer,
+ "*: %s", _("padding")));
+ add_child (::make_unique <text_widget> (std::move (s)));
+ }
+ for (int i = 0; i < (int)m_footnote_fields.size (); i++)
+ {
+ tree field = m_footnote_fields[i];
+ styled_string s (styled_string::from_fmt (sm, default_tree_printer,
+ "(%i): %qE",
+ i + 1, field));
+ add_child (::make_unique <text_widget> (std::move (s)));
+ }
+}
+
+text_art::table::coord_t
+layout_diagram::bit_to_table_coord (bit_offset_t bit)
+{
+ return text_art::table::coord_t ((bit % 32).to_shwi () + 2,
+ (bit / 32).to_shwi () + 2);
+}
+
+void
+layout_diagram::ensure_table_rows (text_art::style_manager &sm,
+ text_art::table &table,
+ int table_y)
+{
+ using namespace text_art;
+
+ while (table_y >= table.get_size ().h)
+ {
+ const int word = table.get_size ().h - 2;
+ table.add_row ();
+ table.set_cell (table::coord_t (0, word + 2),
+ styled_string::from_fmt (sm, nullptr,
+ "%i", word * 4));
+ table.set_cell (table::coord_t (1, word + 2),
+ styled_string::from_fmt (sm, nullptr,
+ "%i", word * 32));
+ }
+}
+
+text_art::styled_string
+layout_diagram::get_string_for_item (const ana::record_layout::item &item,
+ text_art::style_manager &sm)
+{
+ if (item.m_bit_range.m_size_in_bits > 1)
+ {
+ if (item.m_is_padding)
+ return text_art::styled_string (sm, _("padding"));
+ else
+ return text_art::styled_string::from_fmt
+ (sm, default_tree_printer,
+ "%qE", item.m_field);
+ }
+ else
+ {
+ /* To avoid bloating the table, for 1-bit items, add footnotes of the
+ form "(1)", "(2)", ... for fields, and "*" for padding. */
+ if (item.m_is_padding)
+ {
+ m_has_short_padding = true;
+ return text_art::styled_string ('*');
+ }
+ else
+ {
+ m_footnote_fields.push_back (item.m_field);
+ return text_art::styled_string::from_fmt
+ (sm, nullptr, "(%i)",
+ (int)m_footnote_fields.size ());
+ }
+ }
+}
+
+static void
+impl_show_record_layout (location_t loc,
+ tree type,
+ tree size)
+{
+ gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+ gcc_assert (size == error_mark_node
+ || TREE_CODE (size) == INTEGER_CST);
+
+ const text_art::theme *theme = global_dc->m_diagrams.m_theme;
+ if (!theme)
+ {
+ inform (loc, "not showing layout of %qT; %qs is %qs",
+ type,
+ "-fdiagnostics-text-art-charset", "none");
+ return;
+ }
+
+ /* Generate canvas. */
+ ana::record_layout layout (type);
+ text_art::style_manager sm;
+ ana::layout_diagram diagram (layout, sm, *theme);
+ text_art::canvas canvas (diagram.to_canvas (sm));
+
+ /* Generate alt-text. */
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = pp_show_color (global_dc->printer);
+ pp_printf (&pp, "Diagram showing layout of %qT", type);
+
+ auto_diagnostic_group d;
+ if (size != error_mark_node)
+ inform (loc, "%<sizeof(%T)%> == %E; layout:",
+ type, size);
+ else
+ inform (loc, "layout of %qT", type);
+ diagnostic_emit_diagram (global_dc,
+ diagnostic_diagram (canvas,
+ pp_formatted_text (&pp)));
+}
+
} // namespace ana
#endif /* #if ENABLE_ANALYZER */
+
+void
+show_record_layout (location_t loc ATTRIBUTE_UNUSED,
+ tree type ATTRIBUTE_UNUSED,
+ tree size ATTRIBUTE_UNUSED)
+{
+ gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+
+#if ENABLE_ANALYZER
+ ana::impl_show_record_layout (loc, type, size);
+#else
+ sorry_no_analyzer ();
+#endif /* #if ENABLE_ANALYZER */
+}
@@ -25,12 +25,16 @@ along with GCC; see the file COPYING3. If not see
namespace ana {
+class layout_diagram;
+
/* Information of the layout of a RECORD_TYPE, capturing it as a vector
of items, where each item is either a field or padding. */
class record_layout
{
public:
+ friend class layout_diagram;
+
/* An item within a record; either a field, or padding after a field. */
struct item
{
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "opts.h"
#include "plugin.h"
#include "opt-suggestions.h"
+#include "stor-layout.h"
label_text
get_doc_url (const char *doc_url_suffix)
@@ -1688,6 +1689,98 @@ handle_pragma_message (cpp_reader *)
TREE_STRING_POINTER (message));
}
+/* Subclass of pragma_parser for use when parsing '#pragma GCC show_layout'. */
+
+class pragma_parser_show_layout : public pragma_parser
+{
+public:
+ pragma_parser_show_layout ()
+ : pragma_parser ("GCC", "show_layout", nullptr)
+ {
+ }
+
+ bool require_id (const char *str)
+ {
+ location_t loc = UNKNOWN_LOCATION;
+ tree x = NULL_TREE;
+
+ enum cpp_ttype ttype = pragma_lex (&x, &loc);
+ if (ttype != CPP_NAME
+ || strcmp (IDENTIFIER_POINTER (x), str))
+ {
+ warning_at (loc, OPT_Wpragmas,
+ "ignoring malformed %<#pragma GCC show_layout%>:"
+ " expected %qs", str);
+ return false;
+ }
+ return true;
+ }
+
+ tree require_struct_tag ()
+ {
+ location_t loc = UNKNOWN_LOCATION;
+ tree tag = NULL_TREE;
+
+ enum cpp_ttype ttype = pragma_lex (&tag, &loc);
+ if (ttype != CPP_NAME)
+ {
+ warning_at (loc, OPT_Wpragmas,
+ "ignoring malformed %<#pragma GCC show_layout%>:"
+ " expected struct tag");
+ return NULL_TREE;
+ }
+
+ tree type = identifier_global_tag (tag);
+ if (type == NULL_TREE)
+ {
+ warning_at (loc, OPT_Wpragmas,
+ "ignoring malformed %<#pragma GCC show_layout%>:"
+ " unknown struct tag %qs",
+ IDENTIFIER_POINTER (tag));
+ return NULL_TREE;
+ }
+ if (TREE_CODE (type) != RECORD_TYPE)
+ {
+ warning_at (loc, OPT_Wpragmas,
+ "ignoring malformed %<#pragma GCC show_layout%>:"
+ " expected struct tag");
+ return NULL_TREE;
+ }
+
+ return type;
+ }
+};
+
+/* Handler for '#pragma GCC show_layout'. */
+
+static void
+handle_pragma_show_layout (cpp_reader *)
+{
+ pragma_parser_show_layout p;
+
+ if (c_dialect_cxx ())
+ {
+ if (warn_unknown_pragmas > in_system_header_at (input_location))
+ warning (OPT_Wunknown_pragmas,
+ "%<#pragma GCC show_layout%> is not supported for C++");
+ return;
+ }
+
+ if (!p.require_open_paren ())
+ return;
+ if (!p.require_id ("struct"))
+ return;
+ tree type = p.require_struct_tag ();
+ if (!type)
+ return;
+ if (!p.require_close_paren ())
+ return;
+ gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+
+ tree size = c_sizeof_or_alignof_type (input_location, type, true, false, 0);
+ show_record_layout (input_location, type, size);
+}
+
/* Ignore a no-op pragma that GCC recognizes, but which has no effect. */
static void
handle_pragma_ignore (cpp_reader *)
@@ -2201,6 +2294,8 @@ init_pragma (void)
c_register_pragma (0, "scalar_storage_order",
handle_pragma_scalar_storage_order);
+ c_register_pragma ("GCC", "show_layout", handle_pragma_show_layout);
+
/* Allow plugins to register their own pragmas. */
invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL);
}
@@ -24376,6 +24376,7 @@ information.
* Push/Pop Macro Pragmas::
* Function Specific Option Pragmas::
* Loop-Specific Pragmas::
+* Other Pragmas::
@end menu
@node AArch64 Pragmas
@@ -25001,6 +25002,54 @@ The values of @math{0} and @math{1} block any unrolling of the loop.
@end table
+@node Other Pragmas
+@subsection Other Pragmas
+
+@table @code
+@cindex pragma GCC show_layout
+@item #pragma GCC show_layout
+
+With this pragma, the compiler will emit a diagram showing the in-memory
+layout of a particular @code{struct}, with the relative locations and sizes
+of fields and of padding.
+
+For example, given this contrived usage:
+
+@smallexample
+struct example @{
+ char foo : 7;
+ char bar;
+ char visible : 1;
+ char active : 1;
+@};
+#pragma GCC show_layout(struct example)
+@end smallexample
+
+the compiler will emit output similar to the following:
+
+@smallexample
+note: 'sizeof(struct example)' == 3; layout:
+
+ ┌───────┬────┬───────────────┬─────────────────────┬─────────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼───┬───┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16 │17 │18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼───┼───┼──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┘
+ │ 0 │ 0 │ 'foo' │*│ 'bar' │(1)│(2)│ padding │
+ └───────┴────┴─────────────┴─┴─────────────────────┴───┴───┴─────────────────┘
+ *: padding
+ (1): 'visible'
+ (2): 'active'
+@end smallexample
+
+The output is intended for humans, rather than scripts, and is
+subject to change.
+
+This pragma is not available from C++. It is also not available when GCC
+has been configured without support for the analyzer.
+
+@end table
+
@node Unnamed Fields
@section Unnamed Structure and Union Fields
@cindex @code{struct}
@@ -113,4 +113,7 @@ extern void relayout_decl (tree);
belongs to a function parameter. */
extern tree variable_size (tree);
+/* Implemented in analyzer/record-layout.cc */
+extern void show_record_layout (location_t loc, tree type, tree size);
+
#endif // GCC_STOR_LAYOUT_H
new file mode 100644
@@ -0,0 +1,15 @@
+/* Test that we provide good warnings for malformed '#pragma show_layout'. */
+
+/* { dg-do compile } */
+
+#pragma GCC show_layout /* { dg-warning "ignoring malformed '#pragma GCC show_layout': expected '\\('" } */
+
+#pragma GCC show_layout( /* { dg-warning "ignoring malformed '#pragma GCC show_layout': expected 'struct'" } */
+
+#pragma GCC show_layout(struct /* { dg-warning "ignoring malformed '#pragma GCC show_layout': expected struct tag" } */
+
+#pragma GCC show_layout(struct foo /* { dg-warning "32: ignoring malformed '#pragma GCC show_layout': unknown struct tag 'foo'" } */
+
+union not_a_struct { int placeholder; };
+
+#pragma GCC show_layout(struct not_a_struct /* { dg-warning "32: ignoring malformed '#pragma GCC show_layout': expected struct tag" } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+
+#include <stdint.h>
+
+struct foo
+{
+ int32_t i;
+ int16_t j;
+ int32_t k;
+};
+
+#pragma GCC show_layout(struct foo) /* { dg-message "not showing layout of 'struct foo'; '-fdiagnostics-text-art-charset' is 'none'" } */
new file mode 100644
@@ -0,0 +1,184 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target analyzer } */
+/* { dg-options "-fdiagnostics-text-art-charset=unicode" } */
+
+#include <stdint.h>
+
+struct empty {};
+#pragma GCC show_layout(struct empty) /* { dg-message "sizeof\\(struct empty\\)' == 0; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ └───────┴────┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+
+ { dg-end-multiline-output "" } */
+
+
+struct st_1
+{
+ int32_t i;
+ int16_t j;
+ int32_t k;
+};
+#pragma GCC show_layout(struct st_1) /* { dg-message "sizeof\\(struct st_1\\)' == 12; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+ │ 0 │ 0 │ 'i' │
+ ├───────┼────┼─────────────────────────────────────┬───────────────────────────────────────────────┤
+ │ 4 │ 32 │ 'j' │ padding │
+ ├───────┼────┼─────────────────────────────────────┴───────────────────────────────────────────────┤
+ │ 8 │ 64 │ 'k' │
+ └───────┴────┴─────────────────────────────────────────────────────────────────────────────────────┘
+
+ { dg-end-multiline-output "" } */
+
+
+struct st_2
+{
+ int16_t a;
+ char buf[40];
+};
+#pragma GCC show_layout(struct st_2) /* { dg-message "sizeof\\(struct st_2\\)' == 42; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+ │ 0 │ 0 │ 'a' │ 'buf' │
+ ├───────┼────┼─────────────────────────────────────┴───────────────────────────────────────────────┤
+ │ 4 │ 32 │ │
+ ├───────┼────┤ │
+ │ 8 │ 64 │ │
+ ├───────┼────┤ │
+ │ 12 │ 96 │ │
+ ├───────┼────┤ │
+ │ 16 │128 │ │
+ ├───────┼────┤ │
+ │ 20 │160 │ 'buf' │
+ ├───────┼────┤ │
+ │ 24 │192 │ │
+ ├───────┼────┤ │
+ │ 28 │224 │ │
+ ├───────┼────┤ │
+ │ 32 │256 │ │
+ ├───────┼────┤ │
+ │ 36 │288 │ │
+ ├───────┼────┼─────────────────────────────────────┬───────────────────────────────────────────────┘
+ │ 40 │320 │ 'buf' │
+ └───────┴────┴─────────────────────────────────────┘
+
+ { dg-end-multiline-output "" } */
+
+
+struct st_3
+{
+ int foo : 1;
+ int bar : 2;
+};
+#pragma GCC show_layout(struct st_3) /* { dg-message "sizeof\\(struct st_3\\)' == 4; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼───┬──┬──┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │ 0 │1 │2 │3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼───┼──┴──┼─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+ │ 0 │ 0 │(1)│'bar'│ padding │
+ └───────┴────┴───┴─────┴───────────────────────────────────────────────────────────────────────────────┘
+ (1): 'foo'
+
+ { dg-end-multiline-output "" } */
+
+
+struct st_4
+{
+ char ch;
+};
+#pragma GCC show_layout(struct st_4) /* { dg-message "sizeof\\(struct st_4\\)' == 1; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+ │ 0 │ 0 │ 'ch' │
+ └───────┴────┴───────────────┘
+
+ { dg-end-multiline-output "" } */
+
+
+struct st_5
+{
+ int foo : 7;
+ char bar;
+};
+#pragma GCC show_layout(struct st_5) /* { dg-message "sizeof\\(struct st_5\\)' == 4; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+ │ 0 │ 0 │ 'foo' │*│ 'bar' │ padding │
+ └───────┴────┴─────────────┴─┴─────────────────────┴───────────────────────────────────────────────┘
+ *: padding
+
+ { dg-end-multiline-output "" } */
+
+
+struct st_5a
+{
+ char foo : 7;
+ char bar;
+};
+#pragma GCC show_layout(struct st_5a) /* { dg-message "sizeof\\(struct st_5a\\)' == 2; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+ │ 0 │ 0 │ 'foo' │*│ 'bar' │
+ └───────┴────┴─────────────┴─┴─────────────────────┘
+ *: padding
+
+ { dg-end-multiline-output "" } */
+
+
+/* Example from docs. */
+
+struct example
+{
+ char foo : 7;
+ char bar;
+ char visible : 1;
+ char active : 1;
+};
+#pragma GCC show_layout(struct example) /* { dg-message "sizeof\\(struct example\\)' == 3; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────┬─────────────────────┬─────────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼───┬───┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16 │17 │18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼───┼───┼──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┘
+ │ 0 │ 0 │ 'foo' │*│ 'bar' │(1)│(2)│ padding │
+ └───────┴────┴─────────────┴─┴─────────────────────┴───┴───┴─────────────────┘
+ *: padding
+ (1): 'visible'
+ (2): 'active'
+
+ { dg-end-multiline-output "" } */
new file mode 100644
@@ -0,0 +1,175 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target analyzer } */
+/* { dg-options "-fdiagnostics-text-art-charset=unicode" } */
+
+typedef unsigned int __u32;
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+/* Adapted from Linux: drivers/scsi/aacraid/aacraid.h */
+
+struct aac_hba_info {
+
+ u8 driver_name[50];
+ u8 adapter_number;
+ u8 system_io_bus_number;
+ u8 device_number;
+ u32 function_number;
+ u32 vendor_id;
+ u32 device_id;
+ u32 sub_vendor_id;
+ u32 sub_system_id;
+ u32 mapped_base_address_size;
+ u32 base_physical_address_high_part;
+ u32 base_physical_address_low_part;
+
+ u32 max_command_size;
+ u32 max_fib_size;
+ u32 max_scatter_gather_from_os;
+ u32 max_scatter_gather_to_fw;
+ u32 max_outstanding_fibs;
+
+ u32 queue_start_threshold;
+ u32 queue_dump_threshold;
+ u32 max_io_size_queued;
+ u32 outstanding_io;
+
+ u32 firmware_build_number;
+ u32 bios_build_number;
+ u32 driver_build_number;
+ u32 serial_number_high_part;
+ u32 serial_number_low_part;
+ u32 supported_options;
+ u32 feature_bits;
+ u32 currentnumber_ports;
+
+ u8 new_comm_interface:1;
+ u8 new_commands_supported:1;
+ u8 disable_passthrough:1;
+ u8 expose_non_dasd:1;
+ u8 queue_allowed:1;
+ u8 bled_check_enabled:1;
+ u8 reserved1:1;
+ u8 reserted2:1;
+
+ u32 reserved3[10];
+};
+
+#pragma GCC show_layout(struct aac_hba_info) /* { dg-message "sizeof\\(struct aac_hba_info\\)' == 200; layout:" }
+ /* { dg-begin-multiline-output "" }
+
+ ┌───────┬────┬───────────────────────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+ │Offsets│Byte│ 0 │ 1 │ 2 │ 3 │
+ ├───────┼────┼───┬───┬───┬───┬───┬───┬───┬───┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+ │ Byte │Bit │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+ ├───────┼────┼───┴───┴───┴───┴───┴───┴───┴───┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+ │ 0 │ 0 │ │
+ ├───────┼────┤ │
+ │ 4 │ 32 │ │
+ ├───────┼────┤ │
+ │ 8 │ 64 │ │
+ ├───────┼────┤ │
+ │ 12 │ 96 │ │
+ ├───────┼────┤ │
+ │ 16 │128 │ │
+ ├───────┼────┤ │
+ │ 20 │160 │ │
+ ├───────┼────┤ 'driver_name' │
+ │ 24 │192 │ │
+ ├───────┼────┤ │
+ │ 28 │224 │ │
+ ├───────┼────┤ │
+ │ 32 │256 │ │
+ ├───────┼────┤ │
+ │ 36 │288 │ │
+ ├───────┼────┤ │
+ │ 40 │320 │ │
+ ├───────┼────┤ │
+ │ 44 │352 │ │
+ ├───────┼────┼─────────────────────────────────────────────────────┬───────────────────────┬───────────────────────┤
+ │ 48 │384 │ 'driver_name' │ 'adapter_number' │'system_io_bus_number' │
+ ├───────┼────┼───────────────────────────────┬─────────────────────┴───────────────────────┴───────────────────────┤
+ │ 52 │416 │ 'device_number' │ padding │
+ ├───────┼────┼───────────────────────────────┴─────────────────────────────────────────────────────────────────────┤
+ │ 56 │448 │ 'function_number' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 60 │480 │ 'vendor_id' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 64 │512 │ 'device_id' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 68 │544 │ 'sub_vendor_id' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 72 │576 │ 'sub_system_id' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 76 │608 │ 'mapped_base_address_size' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 80 │640 │ 'base_physical_address_high_part' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 84 │672 │ 'base_physical_address_low_part' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 88 │704 │ 'max_command_size' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 92 │736 │ 'max_fib_size' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 96 │768 │ 'max_scatter_gather_from_os' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 100 │800 │ 'max_scatter_gather_to_fw' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 104 │832 │ 'max_outstanding_fibs' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 108 │864 │ 'queue_start_threshold' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 112 │896 │ 'queue_dump_threshold' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 116 │928 │ 'max_io_size_queued' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 120 │960 │ 'outstanding_io' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 124 │992 │ 'firmware_build_number' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 128 │1024│ 'bios_build_number' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 132 │1056│ 'driver_build_number' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 136 │1088│ 'serial_number_high_part' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 140 │1120│ 'serial_number_low_part' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 144 │1152│ 'supported_options' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 148 │1184│ 'feature_bits' │
+ ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 152 │1216│ 'currentnumber_ports' │
+ ├───────┼────┼───┬───┬───┬───┬───┬───┬───┬───┬─────────────────────────────────────────────────────────────────────┤
+ │ 156 │1248│(1)│(2)│(3)│(4)│(5)│(6)│(7)│(8)│ padding │
+ ├───────┼────┼───┴───┴───┴───┴───┴───┴───┴───┴─────────────────────────────────────────────────────────────────────┤
+ │ 160 │1280│ │
+ ├───────┼────┤ │
+ │ 164 │1312│ │
+ ├───────┼────┤ │
+ │ 168 │1344│ │
+ ├───────┼────┤ │
+ │ 172 │1376│ │
+ ├───────┼────┤ │
+ │ 176 │1408│ │
+ ├───────┼────┤ 'reserved3' │
+ │ 180 │1440│ │
+ ├───────┼────┤ │
+ │ 184 │1472│ │
+ ├───────┼────┤ │
+ │ 188 │1504│ │
+ ├───────┼────┤ │
+ │ 192 │1536│ │
+ ├───────┼────┤ │
+ │ 196 │1568│ │
+ └───────┴────┴─────────────────────────────────────────────────────────────────────────────────────────────────────┘
+ (1): 'new_comm_interface'
+ (2): 'new_commands_supported'
+ (3): 'disable_passthrough'
+ (4): 'expose_non_dasd'
+ (5): 'queue_allowed'
+ (6): 'bled_check_enabled'
+ (7): 'reserved1'
+ (8): 'reserted2'
+
+ { dg-end-multiline-output "" } */