@@ -1,3 +1,24 @@
+2014-07-09 Mark Wielaard <mjw@redhat.com>
+
+ * c-typeprint.c (cp_type_print_method_args): Handle TYPE_USER_ALIGN.
+ (c_type_print_varspec_prefix): Likewise.
+ (c_type_print_modifier): Likewise.
+ * dwarf2read.c (add_array_cv_aligned_type): New function.
+ (read_tag_aligned_type): Likewise.
+ (read_type_die_1): Handle DW_TAG_aligned_type.
+ * gdbtypes.c (make_qualified_type): Calls...
+ (make_qualified_aligned_type): New function that handles user
+ alignment.
+ (make_aligned_type): New function.
+ (check_typedef): Handle TYPE_USER_ALIGN.
+ (check_types_equal): Likewise.
+ (recursive_dump_type): Likewise.
+ (copy_type_recursive): Likewise.
+ (copy_type): Likewise.
+ * gdbtypes.h (struct type): Add user_align.
+ (TYPE_USER_ALIGN): New define.
+ (make_aligned_type): Define.
+
2014-07-08 Markus Metzger <markus.t.metzger@intel.com>
* infcmd.c (finish_backward): Turn internal error into normal error.
@@ -275,6 +275,9 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
if (TYPE_ATOMIC (domain))
fprintf_filtered (stream, " _Atomic");
+
+ if (TYPE_USER_ALIGN (domain) != 0)
+ fprintf_filtered (stream, " _Alignas (%u)", TYPE_USER_ALIGN (domain));
}
}
@@ -313,6 +316,9 @@ c_type_print_varspec_prefix (struct type *type,
case TYPE_CODE_PTR:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
stream, show, 1, 1, flags);
+ /* _Alignas comes before the "*' pointer unlike the other modifiers. */
+ if (TYPE_USER_ALIGN (type) != 0)
+ fprintf_filtered (stream, " _Alignas (%u) ", TYPE_USER_ALIGN (type));
fprintf_filtered (stream, "*");
c_type_print_modifier (type, stream, 1, need_post_space);
break;
@@ -394,8 +400,8 @@ c_type_print_varspec_prefix (struct type *type,
}
}
-/* Print out "const" and "volatile" attributes,
- and address space id if present.
+/* Print out "const", "volatile", "restrict", "_Atomic" and "_Alignas"
+ attributes, and address space id if present.
TYPE is a pointer to the type being printed out.
STREAM is the output destination.
NEED_PRE_SPACE = 1 indicates an initial white space is needed.
@@ -444,6 +450,15 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
did_print_modifier = 1;
}
+ /* For pointers the _Alignas comes before the '*'. */
+ if (TYPE_USER_ALIGN (type) != 0 && TYPE_CODE (type) != TYPE_CODE_PTR)
+ {
+ if (did_print_modifier || need_pre_space)
+ fprintf_filtered (stream, " ");
+ fprintf_filtered (stream, "_Alignas (%u)", TYPE_USER_ALIGN (type));
+ did_print_modifier = 1;
+ }
+
address_space_id = address_space_int_to_name (get_type_arch (type),
TYPE_INSTANCE_FLAGS (type));
if (address_space_id)
@@ -14128,6 +14128,33 @@ add_array_cv_type (struct die_info *die, struct dwarf2_cu *cu,
return set_die_type (die, base_type, cu);
}
+/* Add the given user alignment to the element type of the array. GCC
+ outputs DWARF type qualifiers that apply to an array, not the
+ element type. But GDB relies on the array element type to carry
+ the cv-qualifiers. This is mimics section 6.7.3, point 9 of the
+ C11 specification (n1570). */
+static struct type *
+add_array_cv_aligned_type (struct die_info *die, struct dwarf2_cu *cu,
+ struct type *base_type, unsigned int user_align)
+{
+ struct type *el_type, *inner_array;
+
+ base_type = copy_type (base_type);
+ inner_array = base_type;
+
+ while (TYPE_CODE (TYPE_TARGET_TYPE (inner_array)) == TYPE_CODE_ARRAY)
+ {
+ TYPE_TARGET_TYPE (inner_array) =
+ copy_type (TYPE_TARGET_TYPE (inner_array));
+ inner_array = TYPE_TARGET_TYPE (inner_array);
+ }
+
+ el_type = TYPE_TARGET_TYPE (inner_array);
+ TYPE_TARGET_TYPE (inner_array) = make_aligned_type (el_type, user_align);
+
+ return set_die_type (die, base_type, cu);
+}
+
static struct type *
read_tag_const_type (struct die_info *die, struct dwarf2_cu *cu)
{
@@ -14205,6 +14232,34 @@ read_tag_atomic_type (struct die_info *die, struct dwarf2_cu *cu)
return set_die_type (die, cv_type, cu);
}
+static struct type *
+read_tag_aligned_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *base_type, *align_type;
+ struct attribute *attr;
+ unsigned int user_align = 0;
+
+ base_type = die_type (die, cu);
+
+ /* The die_type call above may have already set the type for this DIE. */
+ align_type = get_die_type (die, cu);
+ if (align_type)
+ return align_type;
+
+ attr = dwarf2_attr (die, DW_AT_alignment, cu);
+ if (attr)
+ user_align = DW_UNSND (attr);
+
+ /* In case the _Alignas qualifier is applied to an array type, the
+ element type is so qualified, not the array type (section 6.7.3
+ of C99). */
+ if (TYPE_CODE (base_type) == TYPE_CODE_ARRAY)
+ return add_array_cv_aligned_type (die, cu, base_type, user_align);
+
+ align_type = make_aligned_type (base_type, user_align);
+ return set_die_type (die, align_type, cu);
+}
+
/* Extract all information from a DW_TAG_string_type DIE and add to
the user defined type vector. It isn't really a user defined type,
but it behaves like one, with other DIE's using an AT_user_def_type
@@ -18538,6 +18593,9 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
case DW_TAG_atomic_type:
this_type = read_tag_atomic_type (die, cu);
break;
+ case DW_TAG_aligned_type:
+ this_type = read_tag_aligned_type (die, cu);
+ break;
default:
complaint (&symfile_complaints,
_("unexpected tag in read_type_die: '%s'"),
@@ -565,21 +565,23 @@ address_space_int_to_name (struct gdbarch *gdbarch, int space_flag)
return NULL;
}
-/* Create a new type with instance flags NEW_FLAGS, based on TYPE.
+/* Create a new type with instance flags NEW_FLAGS, and NEW_ALIGN (if
+ stricter) based on TYPE.
If STORAGE is non-NULL, create the new type instance there.
STORAGE must be in the same obstack as TYPE. */
static struct type *
-make_qualified_type (struct type *type, int new_flags,
- struct type *storage)
+make_qualified_aligned_type (struct type *type, int new_flags,
+ unsigned int new_align, struct type *storage)
{
struct type *ntype;
ntype = type;
do
{
- if (TYPE_INSTANCE_FLAGS (ntype) == new_flags)
+ if (TYPE_INSTANCE_FLAGS (ntype) == new_flags
+ && TYPE_USER_ALIGN (ntype) == new_align)
return ntype;
ntype = TYPE_CHAIN (ntype);
}
@@ -616,9 +618,25 @@ make_qualified_type (struct type *type, int new_flags,
/* Set length of new type to that of the original type. */
TYPE_LENGTH (ntype) = TYPE_LENGTH (type);
+ /* If new user alignment is stricter (bigger) than the original type
+ then use it, otherwise take the user alignment of the original
+ type. */
+ if (new_align > TYPE_USER_ALIGN (type))
+ TYPE_USER_ALIGN (ntype) = new_align;
+ else
+ TYPE_USER_ALIGN (ntype) = TYPE_USER_ALIGN (type);
+
return ntype;
}
+static struct type *
+make_qualified_type (struct type *type, int new_flags,
+ struct type *storage)
+{
+ return make_qualified_aligned_type (type, new_flags,
+ TYPE_USER_ALIGN (type), storage);
+}
+
/* Make an address-space-delimited variant of a type -- a type that
is identical to the one supplied except that it has an address
space attribute attached to it (such as "code" or "data").
@@ -717,6 +735,19 @@ make_atomic_type (struct type *type)
NULL);
}
+/* Make a '_Alignas'-qualified version of TYPE (if user_align is
+ stricter than the user alignment of TYPE). */
+
+struct type *
+make_aligned_type (struct type *type, unsigned int user_align)
+{
+ if (user_align > TYPE_USER_ALIGN (type))
+ return make_qualified_aligned_type (type, TYPE_INSTANCE_FLAGS (type),
+ user_align, NULL);
+ else
+ return type;
+}
+
/* Replace the contents of ntype with the type *type. This changes the
contents, rather than the pointer for TYPE_MAIN_TYPE (ntype); thus
the changes are propogated to all types in the TYPE_CHAIN.
@@ -1888,9 +1919,9 @@ resolve_dynamic_type (struct type *type, CORE_ADDR addr)
types. Completion changes the TYPE argument, but stripping of
typedefs does not.
- Instance flags (e.g. const/volatile) are preserved as typedefs are
- stripped. If necessary a new qualified form of the underlying type
- is created.
+ Instance flags (e.g. const/volatile/restrict) are preserved as typedefs
+ are stripped. And user alignment is resolved to the strictest alignment.
+ If necessary a new qualified form of the underlying type is created.
NOTE: This will return a typedef if TYPE_TARGET_TYPE for the typedef has
not been computed and we're either in the middle of reading symbols, or
@@ -1916,8 +1947,9 @@ check_typedef (struct type *type)
{
struct type *orig_type = type;
/* While we're removing typedefs, we don't want to lose qualifiers.
- E.g., const/volatile. */
+ E.g., const/volatile/restrict. Or the (strictest) user alignment. */
int instance_flags = TYPE_INSTANCE_FLAGS (type);
+ unsigned int user_align = TYPE_USER_ALIGN (type);
gdb_assert (type);
@@ -1931,7 +1963,8 @@ check_typedef (struct type *type)
/* It is dangerous to call lookup_symbol if we are currently
reading a symtab. Infinite recursion is one danger. */
if (currently_reading_symtab)
- return make_qualified_type (type, instance_flags, NULL);
+ return make_qualified_aligned_type (type, instance_flags,
+ user_align, NULL);
name = type_name_no_tag (type);
/* FIXME: shouldn't we separately check the TYPE_NAME and
@@ -1941,7 +1974,8 @@ check_typedef (struct type *type)
if (name == NULL)
{
stub_noname_complaint ();
- return make_qualified_type (type, instance_flags, NULL);
+ return make_qualified_aligned_type (type, instance_flags,
+ user_align, NULL);
}
sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0);
if (sym)
@@ -1967,6 +2001,7 @@ check_typedef (struct type *type)
| TYPE_INSTANCE_FLAG_DATA_SPACE);
const int ALL_CLASSES = TYPE_INSTANCE_FLAG_ADDRESS_CLASS_ALL;
int new_instance_flags = TYPE_INSTANCE_FLAGS (type);
+ int new_user_align = TYPE_USER_ALIGN (type);
/* Treat code vs data spaces and address classes separately. */
if ((instance_flags & ALL_SPACES) != 0)
@@ -1975,6 +2010,8 @@ check_typedef (struct type *type)
new_instance_flags &= ~ALL_CLASSES;
instance_flags |= new_instance_flags;
+ if (new_user_align > user_align)
+ user_align = new_user_align;
}
}
@@ -1994,7 +2031,8 @@ check_typedef (struct type *type)
if (name == NULL)
{
stub_noname_complaint ();
- return make_qualified_type (type, instance_flags, NULL);
+ return make_qualified_aligned_type (type, instance_flags,
+ user_align, NULL);
}
newtype = lookup_transparent_type (name);
@@ -2011,9 +2049,10 @@ check_typedef (struct type *type)
move over any other types NEWTYPE refers to, which could
be an unbounded amount of stuff. */
if (TYPE_OBJFILE (newtype) == TYPE_OBJFILE (type))
- type = make_qualified_type (newtype,
- TYPE_INSTANCE_FLAGS (type),
- type);
+ type = make_qualified_aligned_type (newtype,
+ TYPE_INSTANCE_FLAGS (type),
+ TYPE_USER_ALIGN (type),
+ type);
else
type = newtype;
}
@@ -2032,7 +2071,8 @@ check_typedef (struct type *type)
if (name == NULL)
{
stub_noname_complaint ();
- return make_qualified_type (type, instance_flags, NULL);
+ return make_qualified_aligned_type (type, instance_flags,
+ user_align, NULL);
}
sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0);
if (sym)
@@ -2041,9 +2081,10 @@ check_typedef (struct type *type)
with the complete type only if they are in the same
objfile. */
if (TYPE_OBJFILE (SYMBOL_TYPE(sym)) == TYPE_OBJFILE (type))
- type = make_qualified_type (SYMBOL_TYPE (sym),
- TYPE_INSTANCE_FLAGS (type),
- type);
+ type = make_qualified_aligned_type (SYMBOL_TYPE (sym),
+ TYPE_INSTANCE_FLAGS (type),
+ TYPE_USER_ALIGN (type),
+ type);
else
type = SYMBOL_TYPE (sym);
}
@@ -2065,7 +2106,7 @@ check_typedef (struct type *type)
}
}
- type = make_qualified_type (type, instance_flags, NULL);
+ type = make_qualified_aligned_type (type, instance_flags, user_align, NULL);
/* Cache TYPE_LENGTH for future use. */
TYPE_LENGTH (orig_type) = TYPE_LENGTH (type);
@@ -2881,7 +2922,8 @@ check_types_equal (struct type *type1, struct type *type2,
|| TYPE_VECTOR (type1) != TYPE_VECTOR (type2)
|| TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
|| TYPE_INSTANCE_FLAGS (type1) != TYPE_INSTANCE_FLAGS (type2)
- || TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
+ || TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2)
+ || TYPE_USER_ALIGN (type1) != TYPE_USER_ALIGN (type2))
return 0;
if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
@@ -3800,6 +3842,10 @@ recursive_dump_type (struct type *type, int spaces)
{
puts_filtered (" TYPE_FLAG_ATOMIC");
}
+ if (TYPE_USER_ALIGN (type) != 0)
+ {
+ printf_filtered (" TYPE_USER_ALIGN (%u)", TYPE_USER_ALIGN (type));
+ }
puts_filtered ("\n");
printfi_filtered (spaces, "flags");
@@ -4038,6 +4084,7 @@ copy_type_recursive (struct objfile *objfile,
TYPE_TAG_NAME (new_type) = xstrdup (TYPE_TAG_NAME (type));
TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
+ TYPE_USER_ALIGN (new_type) = TYPE_USER_ALIGN (type);
TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
/* Copy the fields. */
@@ -4135,6 +4182,7 @@ copy_type (const struct type *type)
new_type = alloc_type_copy (type);
TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
+ TYPE_USER_ALIGN (new_type) = TYPE_USER_ALIGN (type);
TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type),
sizeof (struct main_type));
@@ -752,10 +752,10 @@ struct type
/* * Variant chain. This points to a type that differs from this
one only in qualifiers and length. Currently, the possible
- qualifiers are const, volatile, code-space, data-space, and
- address class. The length may differ only when one of the
- address class flags are set. The variants are linked in a
- circular ring and share MAIN_TYPE. */
+ qualifiers are const, volatile, restrict, code-space, data-space,
+ address class and use alignment. The length may differ only when
+ one of the address class flags are set. The variants are linked
+ in a circular ring and share MAIN_TYPE. */
struct type *chain;
@@ -797,6 +797,12 @@ struct type
unsigned length;
+ /* * User alignment of this type. This is what alignof(type) would
+ return when explicitly set by the user with c11 _Alignas or
+ __attribute__ ((aligned (X)). If not explicitly set by the user
+ it is zero and the default alignment would apply. */
+ unsigned user_align;
+
/* * Core type, shared by a group of qualified types. */
struct main_type *main_type;
@@ -1195,6 +1201,7 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code
#define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields
#define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.fields
+#define TYPE_USER_ALIGN(thistype) (thistype)->user_align
#define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0)
#define TYPE_RANGE_DATA(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.bounds
@@ -1636,6 +1643,8 @@ extern struct type *make_restrict_type (struct type *);
extern struct type *make_atomic_type (struct type *);
+extern struct type *make_aligned_type (struct type *, unsigned int);
+
extern void replace_type (struct type *, struct type *);
extern int address_space_name_to_int (struct gdbarch *, char *);
@@ -1,3 +1,7 @@
+2014-07-09 Mark Wielaard <mjw@redhat.com>
+
+ * dwarf2.def: Add DW_TAG_aligned_type and DW_AT_alignment.
+
2014-06-22 Mark Wielaard <mjw@redhat.com>
* dwarf2.def: Add DW_TAG_atomic_type.
@@ -135,6 +135,7 @@ DW_TAG (DW_TAG_rvalue_reference_type, 0x42)
DW_TAG (DW_TAG_template_alias, 0x43)
/* DWARF 5. */
DW_TAG (DW_TAG_atomic_type, 0x47)
+DW_TAG (DW_TAG_aligned_type, 0x48) /* XXX not yet assigned constant. */
DW_TAG_DUP (DW_TAG_lo_user, 0x4080)
DW_TAG_DUP (DW_TAG_hi_user, 0xffff)
@@ -310,6 +311,8 @@ DW_AT (DW_AT_data_bit_offset, 0x6b)
DW_AT (DW_AT_const_expr, 0x6c)
DW_AT (DW_AT_enum_class, 0x6d)
DW_AT (DW_AT_linkage_name, 0x6e)
+/* DWARF 5. */
+DW_TAG (DW_AT_alignment, 0x6f) /* XXX not yet assigned constant. */
DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */
DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end. */