diff mbox

[2/2] DWARF5: Add DW_TAG_aligned_type support.

Message ID 1407857735-18515-2-git-send-email-mjw@redhat.com
State New
Headers show

Commit Message

Mark Wielaard Aug. 12, 2014, 3:35 p.m. UTC
Ping. As with the patch for DW_TAG_atomic_type this is only experimental
at this time, but feedback appreciated.

There is a corresponding patch for GDB:
https://sourceware.org/ml/gdb-patches/2014-07/msg00199.html

gcc/ChangeLog

	* dwarf2out.c (decl_user_align): New function.
	(type_user_align): Likewise.
	(modified_type_die): Add and handle align argument.
	(add_bound_info): Likewise.
	(base_type_for_mode): Call modified_type_die with zero user align.
	(add_subscript_info): Call add_type_attribute with zero user align.
	(gen_array_type_die): Likewise.
	(gen_descr_array_type_die): Likewise.
	(gen_entry_point_die): Likewise.
	(gen_enumeration_type_die): Likewise.
	(gen_formal_parameter_die): Likewise.
	(gen_subprogram_die): Likewise.
	(gen_variable_die): Likewise.
	(gen_const_die): Likewise.
	(gen_field_die): Likewise.
	(gen_pointer_type_die): Likewise.
	(gen_reference_type_die): Likewise.
	(gen_ptr_to_mbr_type_die): Likewise.
	(gen_inheritance_die): Likewise.
	(gen_subroutine_type_die): Likewise.
	(gen_typedef_die): Likewise.
	(force_type_die): Likewise.

gcc/testsuite/ChangeLog

	* gcc.dg/guality/alignas.c: New test.
---
 gcc/ChangeLog                          |  25 +++++++
 gcc/dwarf2out.c                        | 116 ++++++++++++++++++++++-----------
 gcc/testsuite/ChangeLog                |   4 ++
 gcc/testsuite/gcc.dg/guality/alignas.c |  57 ++++++++++++++++
 include/dwarf2.def                     |   3 +
 5 files changed, 168 insertions(+), 37 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/guality/alignas.c

Comments

Jason Merrill Aug. 12, 2014, 8:05 p.m. UTC | #1
I'm dubious about adding a tag for alignment, because it doesn't 
participate in the type system; in C and C++, it's an attribute of a 
struct or variable declaration, but the variable has the same type as 
another variable without the explicit alignment.  In the GNU extension 
it can also be applied to a typedef, but I think there I'd still put the 
attribute on the typedef rather than introduce a new tag.

Jason
diff mbox

Patch

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1adf6a6..ba37472 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,30 @@ 
 2014-07-09  Mark Wielaard  <mjw@redhat.com>
 
+	* dwarf2out.c (decl_user_align): New function.
+	(type_user_align): Likewise.
+	(modified_type_die): Add and handle align argument.
+	(add_bound_info): Likewise.
+	(base_type_for_mode): Call modified_type_die with zero user align.
+	(add_subscript_info): Call add_type_attribute with zero user align.
+	(gen_array_type_die): Likewise.
+	(gen_descr_array_type_die): Likewise.
+	(gen_entry_point_die): Likewise.
+	(gen_enumeration_type_die): Likewise.
+	(gen_formal_parameter_die): Likewise.
+	(gen_subprogram_die): Likewise.
+	(gen_variable_die): Likewise.
+	(gen_const_die): Likewise.
+	(gen_field_die): Likewise.
+	(gen_pointer_type_die): Likewise.
+	(gen_reference_type_die): Likewise.
+	(gen_ptr_to_mbr_type_die): Likewise.
+	(gen_inheritance_die): Likewise.
+	(gen_subroutine_type_die): Likewise.
+	(gen_typedef_die): Likewise.
+	(force_type_die): Likewise.
+
+2014-07-09  Mark Wielaard  <mjw@redhat.com>
+
 	PR debug/60782
 	* dwarf2out.c (modified_type_die): Handle TYPE_QUAL_ATOMIC.
 	* opts.c (common_handle_option): Accept -gdwarf-5.
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 7792604..c3f1d80 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3142,7 +3142,7 @@  static dw_die_ref base_type_die (tree);
 static int is_base_type (tree);
 static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref);
 static int decl_quals (const_tree);
-static dw_die_ref modified_type_die (tree, int, dw_die_ref);
+static dw_die_ref modified_type_die (tree, int, unsigned int, dw_die_ref);
 static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
 static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
 static int type_is_enum (const_tree);
@@ -3200,7 +3200,7 @@  static dw_die_ref scope_die_for (tree, dw_die_ref);
 static inline int local_scope_p (dw_die_ref);
 static inline int class_scope_p (dw_die_ref);
 static inline int class_or_namespace_scope_p (dw_die_ref);
-static void add_type_attribute (dw_die_ref, tree, int, dw_die_ref);
+static void add_type_attribute (dw_die_ref, tree, int, unsigned int, dw_die_ref);
 static void add_calling_convention_attribute (dw_die_ref, tree);
 static const char *type_tag (const_tree);
 static tree member_declared_type (const_tree);
@@ -10460,11 +10460,30 @@  decl_quals (const_tree decl)
 	     ? TYPE_QUAL_VOLATILE : TYPE_UNQUALIFIED));
 }
 
+static unsigned int
+decl_user_align (const_tree decl)
+{
+  if (DECL_USER_ALIGN (decl))
+    return DECL_ALIGN_UNIT (decl);
+
+  return 0;
+}
+
+static unsigned int
+type_user_align (const_tree type)
+{
+  if (TYPE_USER_ALIGN (type))
+    return TYPE_ALIGN_UNIT (type);
+
+  return 0;
+}
+
 /* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
    entry that chains various modifiers in front of the given type.  */
 
 static dw_die_ref
-modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
+modified_type_die (tree type, int cv_quals, unsigned int align,
+		   dw_die_ref context_die)
 {
   enum tree_code code = TREE_CODE (type);
   dw_die_ref mod_type_die;
@@ -10487,14 +10506,23 @@  modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
   if (dwarf_version < 3)
     cv_quals &= ~TYPE_QUAL_RESTRICT;
 
-  /* Likewise for DW_TAG_atomic_type for DWARFv5.  */
+  /* Likewise for DW_TAG_atomic_type and DW_TAG_aligned_type for DWARFv5.  */
   if (dwarf_version < 5)
-    cv_quals &= ~TYPE_QUAL_ATOMIC;
+    {
+      cv_quals &= ~TYPE_QUAL_ATOMIC;
+      align = 0;
+    }
 
   /* See if we already have the appropriately qualified variant of
      this type.  */
   qualified_type = get_qualified_type (type, cv_quals);
 
+  /* Make sure the qualified type has the correct user alignment if we
+     need one.  */
+  if (align != 0 && qualified_type
+      && type_user_align (qualified_type) != align)
+    qualified_type = NULL_TREE;
+
   if (qualified_type == sizetype
       && TYPE_NAME (qualified_type)
       && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
@@ -10541,7 +10569,7 @@  modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
 	    /* cv-unqualified version of named type.  Just use
 	       the unnamed type to which it refers.  */
 	    return modified_type_die (DECL_ORIGINAL_TYPE (name),
-				      cv_quals, context_die);
+				      cv_quals, align, context_die);
 	  /* Else cv-qualified version of named type; fall through.  */
 	}
     }
@@ -10558,7 +10586,7 @@  modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
     {
       mod_type_die = new_die (DW_TAG_const_type, mod_scope, type);
       sub_die = modified_type_die (type, cv_quals & ~TYPE_QUAL_CONST,
-				   context_die);
+				   align, context_die);
     }
   else if ((cv_quals & TYPE_QUAL_VOLATILE)
 	   && (((cv_quals & ~TYPE_QUAL_VOLATILE) == TYPE_UNQUALIFIED)
@@ -10568,7 +10596,7 @@  modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
     {
       mod_type_die = new_die (DW_TAG_volatile_type, mod_scope, type);
       sub_die = modified_type_die (type, cv_quals & ~TYPE_QUAL_VOLATILE,
-				   context_die);
+				   align, context_die);
     }
   else if ((cv_quals & TYPE_QUAL_RESTRICT)
 	   && (((cv_quals & ~TYPE_QUAL_RESTRICT) == TYPE_UNQUALIFIED)
@@ -10578,13 +10606,19 @@  modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
     {
       mod_type_die = new_die (DW_TAG_restrict_type, mod_scope, type);
       sub_die = modified_type_die (type, cv_quals & ~TYPE_QUAL_RESTRICT,
-				   context_die);
+				   align, context_die);
     }
   else if (cv_quals & TYPE_QUAL_ATOMIC)
     {
       mod_type_die = new_die (DW_TAG_atomic_type, mod_scope, type);
       sub_die = modified_type_die (type, cv_quals & ~TYPE_QUAL_ATOMIC,
-				   context_die);
+				   align, context_die);
+    }
+  else if (align != 0)
+    {
+      mod_type_die = new_die (DW_TAG_aligned_type, mod_scope, type);
+      add_AT_unsigned (mod_type_die, DW_AT_alignment, align);
+      sub_die = modified_type_die (type, cv_quals, 0, context_die);
     }
   else if (code == POINTER_TYPE)
     {
@@ -10675,7 +10709,7 @@  modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
        types are possible in Ada.  */
     sub_die = modified_type_die (item_type,
 				 TYPE_QUALS_NO_ADDR_SPACE (item_type),
-				 context_die);
+				 type_user_align (item_type), context_die);
 
   if (sub_die != NULL)
     add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
@@ -10819,7 +10853,7 @@  generic_parameter_die (tree parm, tree arg,
 	  add_type_attribute (tmpl_die, tmpl_type,
 			      (TREE_THIS_VOLATILE (tmpl_type)
 			       ? TYPE_QUAL_VOLATILE : TYPE_UNQUALIFIED),
-			      parent_die);
+			      0, parent_die);
 	}
       else
 	{
@@ -11560,7 +11594,7 @@  base_type_for_mode (enum machine_mode mode, bool unsignedp)
     }
   type_die = lookup_type_die (type);
   if (!type_die)
-    type_die = modified_type_die (type, TYPE_UNQUALIFIED, comp_unit_die ());
+    type_die = modified_type_die (type, TYPE_UNQUALIFIED, 0, comp_unit_die ());
   if (type_die == NULL || type_die->die_tag != DW_TAG_base_type)
     return NULL;
   return type_die;
@@ -16477,7 +16511,8 @@  add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
 
 	decl_die = new_die (DW_TAG_variable, ctx, bound);
 	add_AT_flag (decl_die, DW_AT_artificial, 1);
-	add_type_attribute (decl_die, TREE_TYPE (bound), TYPE_QUAL_CONST, ctx);
+	add_type_attribute (decl_die, TREE_TYPE (bound), TYPE_QUAL_CONST, 0,
+			    ctx);
 	add_AT_location_description (decl_die, DW_AT_location, list);
 	add_AT_die_ref (subrange_die, bound_attr, decl_die);
 	break;
@@ -16529,7 +16564,7 @@  add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 		;
 	      else
 		add_type_attribute (subrange_die, TREE_TYPE (domain),
-				    TYPE_UNQUALIFIED, type_die);
+				    TYPE_UNQUALIFIED, 0, type_die);
 	    }
 
 	  /* ??? If upper is NULL, the array has unspecified length,
@@ -17025,10 +17060,11 @@  class_or_namespace_scope_p (dw_die_ref context_die)
 
 static void
 add_type_attribute (dw_die_ref object_die, tree type, int cv_quals,
-		    dw_die_ref context_die)
+		    unsigned int align, dw_die_ref context_die)
 {
   enum tree_code code  = TREE_CODE (type);
   dw_die_ref type_die  = NULL;
+  unsigned int type_align;
 
   /* ??? If this type is an unnamed subrange type of an integral, floating-point
      or fixed-point type, use the inner type.  This is because we have no
@@ -17045,8 +17081,10 @@  add_type_attribute (dw_die_ref object_die, tree type, int cv_quals,
       || code == VOID_TYPE)
     return;
 
+  type_align = type_user_align (type);
   type_die = modified_type_die (type,
 				cv_quals | TYPE_QUALS_NO_ADDR_SPACE (type),
+				(type_align > align ? type_align : align),
 				context_die);
 
   if (type_die != NULL)
@@ -17260,7 +17298,8 @@  gen_array_type_die (tree type, dw_die_ref context_die)
 	element_type = TREE_TYPE (element_type);
       }
 
-  add_type_attribute (array_die, element_type, TYPE_UNQUALIFIED, context_die);
+  add_type_attribute (array_die, element_type, TYPE_UNQUALIFIED, 0,
+		      context_die);
 
   add_gnat_descriptive_type_attribute (array_die, type, context_die);
   if (TYPE_ARTIFICIAL (type))
@@ -17423,7 +17462,7 @@  gen_descr_array_type_die (tree type, struct array_descr_info *info,
     }
 
   gen_type_die (info->element_type, context_die);
-  add_type_attribute (array_die, info->element_type, TYPE_UNQUALIFIED,
+  add_type_attribute (array_die, info->element_type, TYPE_UNQUALIFIED, 0,
 		      context_die);
 
   if (get_AT (array_die, DW_AT_name))
@@ -17443,7 +17482,7 @@  gen_entry_point_die (tree decl, dw_die_ref context_die)
     {
       add_name_and_src_coords_attributes (decl_die, decl);
       add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
-			  TYPE_UNQUALIFIED, context_die);
+			  TYPE_UNQUALIFIED, 0, context_die);
     }
 
   if (DECL_ABSTRACT (decl))
@@ -17533,7 +17572,7 @@  gen_enumeration_type_die (tree type, dw_die_ref context_die)
       if (dwarf_version >= 3 || !dwarf_strict)
 	{
 	  tree underlying = lang_hooks.types.enum_underlying_base_type (type);
-	  add_type_attribute (type_die, underlying, TYPE_UNQUALIFIED,
+	  add_type_attribute (type_die, underlying, TYPE_UNQUALIFIED, 0,
 			      context_die);
 	}
       if (TYPE_STUB_DECL (type) != NULL_TREE)
@@ -17636,11 +17675,11 @@  gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 	  tree type = TREE_TYPE (node_or_origin);
 	  if (decl_by_reference_p (node_or_origin))
 	    add_type_attribute (parm_die, TREE_TYPE (type),
-				TYPE_UNQUALIFIED, context_die);
+				TYPE_UNQUALIFIED, 0, context_die);
 	  else
 	    add_type_attribute (parm_die, type,
 				decl_quals (node_or_origin),
-				context_die);
+				decl_user_align (node_or_origin), context_die);
 	}
       if (origin == NULL && DECL_ARTIFICIAL (node))
 	add_AT_flag (parm_die, DW_AT_artificial, 1);
@@ -17655,7 +17694,7 @@  gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 
     case tcc_type:
       /* We were called with some kind of a ..._TYPE node.  */
-      add_type_attribute (parm_die, node_or_origin, TYPE_UNQUALIFIED,
+      add_type_attribute (parm_die, node_or_origin, TYPE_UNQUALIFIED, 0,
 			  context_die);
       break;
 
@@ -18238,7 +18277,7 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	      dw_die_ref die = get_AT_ref (old_die, DW_AT_type);
 	      if (die == auto_die || die == decltype_auto_die)
 		add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
-				    TYPE_UNQUALIFIED, context_die);
+				    TYPE_UNQUALIFIED, 0, context_die);
 	    }
 	}
     }
@@ -18255,7 +18294,7 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  add_prototyped_attribute (subr_die, TREE_TYPE (decl));
 	  add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
-			      TYPE_UNQUALIFIED, context_die);
+			      TYPE_UNQUALIFIED, 0, context_die);
 	}
 
       add_pure_or_virtual_attribute (subr_die, decl);
@@ -18871,7 +18910,7 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       var_die = new_die (DW_TAG_variable, com_die, decl);
       add_name_and_src_coords_attributes (var_die, decl);
       add_type_attribute (var_die, TREE_TYPE (decl), decl_quals (decl),
-			  context_die);
+			  decl_user_align (decl), context_die);
       add_AT_flag (var_die, DW_AT_external, 1);
       if (loc)
 	{
@@ -18964,11 +19003,11 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       tree type = TREE_TYPE (decl_or_origin);
 
       if (decl_by_reference_p (decl_or_origin))
-	add_type_attribute (var_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
+	add_type_attribute (var_die, TREE_TYPE (type), TYPE_UNQUALIFIED, 0,
 			    context_die);
       else
 	add_type_attribute (var_die, type, decl_quals (decl_or_origin),
-			    context_die);
+			    decl_user_align (decl_or_origin), context_die);
     }
 
   if (origin == NULL && !specialization_p)
@@ -19022,7 +19061,7 @@  gen_const_die (tree decl, dw_die_ref context_die)
 
   const_die = new_die (DW_TAG_constant, context_die, decl);
   add_name_and_src_coords_attributes (const_die, decl);
-  add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
+  add_type_attribute (const_die, type, TYPE_QUAL_CONST, 0, context_die);
   if (TREE_PUBLIC (decl))
     add_AT_flag (const_die, DW_AT_external, 1);
   if (DECL_ARTIFICIAL (decl))
@@ -19265,7 +19304,8 @@  gen_field_die (tree decl, dw_die_ref context_die)
   decl_die = new_die (DW_TAG_member, context_die, decl);
   add_name_and_src_coords_attributes (decl_die, decl);
   add_type_attribute (decl_die, member_declared_type (decl),
-		      decl_quals (decl), context_die);
+		      decl_quals (decl), decl_user_align (decl),
+		      context_die);
 
   if (DECL_BIT_FIELD_TYPE (decl))
     {
@@ -19299,7 +19339,7 @@  gen_pointer_type_die (tree type, dw_die_ref context_die)
     = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die), type);
 
   equate_type_number_to_die (type, ptr_die);
-  add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
+  add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED, 0,
 		      context_die);
   add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
 }
@@ -19320,7 +19360,7 @@  gen_reference_type_die (tree type, dw_die_ref context_die)
     ref_die = new_die (DW_TAG_reference_type, scope_die, type);
 
   equate_type_number_to_die (type, ref_die);
-  add_type_attribute (ref_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
+  add_type_attribute (ref_die, TREE_TYPE (type), TYPE_UNQUALIFIED, 0,
 		      context_die);
   add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
 }
@@ -19338,7 +19378,7 @@  gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
   equate_type_number_to_die (type, ptr_die);
   add_AT_die_ref (ptr_die, DW_AT_containing_type,
 		  lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
-  add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
+  add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED, 0,
 		      context_die);
 }
 
@@ -19544,7 +19584,8 @@  gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
 {
   dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
 
-  add_type_attribute (die, BINFO_TYPE (binfo), TYPE_UNQUALIFIED, context_die);
+  add_type_attribute (die, BINFO_TYPE (binfo), TYPE_UNQUALIFIED, 0,
+		      context_die);
   add_data_member_location_attribute (die, binfo);
 
   if (BINFO_VIRTUAL_P (binfo))
@@ -19741,7 +19782,7 @@  gen_subroutine_type_die (tree type, dw_die_ref context_die)
 
   equate_type_number_to_die (type, subr_die);
   add_prototyped_attribute (subr_die, type);
-  add_type_attribute (subr_die, return_type, TYPE_UNQUALIFIED, context_die);
+  add_type_attribute (subr_die, return_type, TYPE_UNQUALIFIED, 0, context_die);
   gen_formal_types_die (type, subr_die);
 
   if (get_AT (subr_die, DW_AT_name))
@@ -19809,7 +19850,8 @@  gen_typedef_die (tree decl, dw_die_ref context_die)
 	    }
 	}
 
-      add_type_attribute (type_die, type, decl_quals (decl), context_die);
+      add_type_attribute (type_die, type, decl_quals (decl),
+			  decl_user_align (decl), context_die);
 
       if (is_naming_typedef_decl (decl))
 	/* We want that all subsequent calls to lookup_type_die with
@@ -20385,7 +20427,7 @@  force_type_die (tree type)
       dw_die_ref context_die = get_context_die (TYPE_CONTEXT (type));
 
       type_die = modified_type_die (type, TYPE_QUALS_NO_ADDR_SPACE (type),
-				    context_die);
+				    type_user_align (type), context_die);
       gcc_assert (type_die);
     }
   return type_die;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4c8ce92..6842fbf 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@ 
 2014-07-09  Mark Wielaard  <mjw@redhat.com>
 
+	* gcc.dg/guality/alignas.c: New test.
+
+2014-07-09  Mark Wielaard  <mjw@redhat.com>
+
 	PR debug/60782
 	* gcc.dg/guality/atomic.c: New test.
 
diff --git a/gcc/testsuite/gcc.dg/guality/alignas.c b/gcc/testsuite/gcc.dg/guality/alignas.c
new file mode 100644
index 0000000..c47b511
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/guality/alignas.c
@@ -0,0 +1,57 @@ 
+/* debuginfo tests for c11 _Alignas. */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -gdwarf-5" } */
+
+#include <stdlib.h>
+#include <malloc.h>
+
+// char normally has alignment 1, say it aligns 8.
+_Alignas (8) char c8;
+
+// multiple alignment requests pick the strictest (largest).
+_Alignas(16) _Alignas(32) _Alignas(8) int i32;
+
+// _Alignas on an array sets alignment of array element type.
+_Alignas(64) unsigned int buf[128];
+
+// Also for const ints.
+const _Alignas (256) unsigned int buf2[] = {0, 1, 2, 3, 4, 5, 6, 8};
+
+// An aligned pointer.
+// (note this applies to the pointer, not to the target type/value).
+unsigned int _Alignas (64) *uiap;
+
+// A const aligned pointer, pointing to a const type (not aligned).
+const unsigned int _Alignas (128) * const cuicap;
+
+// _Alignas on structure field puts offsets at multiples of alignment.
+struct s { int a; _Alignas (16) int bar; };
+
+// Variables of structs can be aligned themselves.
+_Alignas(32) struct s vs = { 1, 14 };
+
+// _Alignas(0) has no effect.
+_Alignas(0) long l;
+
+// And _Alignas can be combined with other qualifiers.
+_Alignas(16) volatile const float vcf16 = 32.0;
+const _Alignas(16) volatile float cvf16 = 64.0;
+
+int
+main (int argc, char **argv)
+{
+  struct s *p = (struct s *) memalign (64, sizeof (struct s));
+  return p == 0;
+}
+
+/* { dg-final { gdb-test 32 "type:c8" "_Alignas (8) char" } } */
+/* { dg-final { gdb-test 32 "type:i32" "_Alignas (32) int" } } */
+/* { dg-final { gdb-test 32 "type:buf" "_Alignas (64) unsigned int \[128\]" } } */
+/* { dg-final { gdb-test 32 "type:buf2" "const _Alignas (256) unsigned int \[8\]" } } */
+/* { dg-final { gdb-test 32 "type:uiap" "unsigned int _Alignas (64) *" } } */
+/* { dg-final { gdb-test 32 "type:cuicap" "const unsigned int _Alignas (128) * const" } } */
+/* { dg-final { gdb-test 32 "type:struct s" "struct s { int a; _Alignas (16) int bar; }" } } */
+/* { dg-final { gdb-test 32 "type:vs" "_Alignas (32) struct s { int a; _Alignas (16) int bar; }" } } */
+/* { dg-final { gdb-test 32 "type:l" "long" } } */
+/* { dg-final { gdb-test 32 "type:vcf16" "const volatile _Alignas (16) float" } } */
+/* { dg-final { gdb-test 32 "type:cvf16" "const volatile _Alignas (16) float" } } */
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 6490391..7ca0704 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -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) /* NOT AN OFFICIAL NUMBER. DWARF5 131112.1 */
+DW_TAG (DW_TAG_aligned_type, 0x48) /* NOT AN OFFICIAL NUMBER. DWARF5 140528.1  */
 
 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) /* NOT AN OFFICIAL NUMBER. DWARF5 140528.1  */
 
 DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start.  */
 DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end.  */