This is yet another follow up on the discussion of the fix for
the ICE in __builtin_has_attribute that started last December
with PR88383.

After my last post last week I went and added more tests to make
sure the built-in behaves as intended by comparing its result for
non-trivial expressions with that of __alignof__.  The test that
does this is the new builtin-has-attribute-7.c.

The test exposed one problem in the handling of attribute vector_size
by the built-in (I mentioned that in my last post).  It also exposed
a couple of bugs in the attribute handler itself.  I fixed both of
these in the attached patch.

This latest revision of the patch resolves the following bugs:

  PR 88383 - ICE calling __builtin_has_attribute on a reference
  PR 89288 - ICE in tree_code_size, at tree.c:865
  PR 89798 - excessive vector_size silently accepted and truncated
  PR 89797 - ICE on a vector_size (1LU << 33) int variable

Bootstrapped on x86_64-linux.  The tests are still running but
assuming they pass, is this last revision good to commit?

Martin

A link to my last comment in the archive:
  https://gcc.gnu.org/ml/gcc-patches/2019-03/msg01096.html
PR c/88383 - ICE calling __builtin_has_attribute on a reference
PR c/89288 - ICE in tree_code_size, at tree.c:865
PR c/89798 - excessive vector_size silently accepted and truncated
PR c/89797 - ICE on a vector_size (1LU << 33) int variable

gcc/ChangeLog:

	PR c/89797
	* targhooks.c (default_vector_alignment): Avoid assuming
	argument fits in SHWI.
	* tree.h (TYPE_VECTOR_SUBPARTS): Avoid sign overflow in
	a shift expression.

gcc/c-family/ChangeLog:

	PR c/88383
	PR c/89288
	PR c/89798
	PR c/89797
	* c-attribs.c (type_valid_for_vector_size): Detect excessively
	large sizes.
	(validate_attribute): Handle DECLs and expressions.
	(has_attribute): Handle types referenced by expressions.
	Avoid considering array attributes in ARRAY_REF expressions .

gcc/cp/ChangeLog:

	PR c/88383
	PR c/89288
	* parser.c (cp_parser_has_attribute_expression): Handle assignment
	expressions.

gcc/testsuite/ChangeLog:

	PR c/88383
	PR c/89288
	PR c/89798
	PR c/89797
	* c-c++-common/attributes-1.c: Adjust.
	* c-c++-common/builtin-has-attribute-6.c: New test.
	* c-c++-common/builtin-has-attribute-7.c: New test.
	* c-c++-common/builtin-has-attribute-4.c: Adjust expectations.
	* c-c++-common/builtin-has-attribute-6.c: New test.
	* gcc.dg/pr25559.c: Adjust.
	* gcc.dg/attr-vector_size.c: New test.
	
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index e559d3b55d2..9ded3df278e 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -3478,19 +3478,56 @@ type_valid_for_vector_size (tree type, tree atname, tree args,
     return type;
 
   tree size = TREE_VALUE (args);
+  /* Erroneous arguments have already been diagnosed.  */
+  if (size == error_mark_node)
+    return NULL_TREE;
+
   if (size && TREE_CODE (size) != IDENTIFIER_NODE
       && TREE_CODE (size) != FUNCTION_DECL)
     size = default_conversion (size);
 
-  if (!tree_fits_uhwi_p (size))
+  if (TREE_CODE (size) != INTEGER_CST)
+    {
+      if (error_p)
+	error ("%qE attribute argument value %qE is not an integer constant",
+	       atname, size);
+      else
+	warning (OPT_Wattributes,
+		 "%qE attribute argument value %qE is not an integer constant",
+		 atname, size);
+      return NULL_TREE;
+    }
+
+  if (!TYPE_UNSIGNED (TREE_TYPE (size))
+      && tree_int_cst_sgn (size) < 0)
     {
-      /* FIXME: make the error message more informative.  */
       if (error_p)
-	warning (OPT_Wattributes, "%qE attribute ignored", atname);
+	error ("%qE attribute argument value %qE is negative",
+	       atname, size);
+      else
+	warning (OPT_Wattributes,
+		 "%qE attribute argument value %qE is negative",
+		 atname, size);
+      return NULL_TREE;
+    }
+
+  /* The attribute argument value is constrained by the maximum bit
+     alignment representable in unsigned int on the host.  */
+  unsigned HOST_WIDE_INT vecsize;
+  unsigned HOST_WIDE_INT maxsize = tree_to_uhwi (max_object_size ());
+  if (!tree_fits_uhwi_p (size)
+      || (vecsize = tree_to_uhwi (size)) > maxsize)
+    {
+      if (error_p)
+	error ("%qE attribute argument value %qE exceeds %wu",
+	       atname, size, maxsize);
+      else
+	warning (OPT_Wattributes,
+		 "%qE attribute argument value %qE exceeds %wu",
+		 atname, size, maxsize);
       return NULL_TREE;
     }
 
-  unsigned HOST_WIDE_INT vecsize = tree_to_uhwi (size);
   if (vecsize % tree_to_uhwi (TYPE_SIZE_UNIT (type)))
     {
       if (error_p)
@@ -4033,8 +4070,12 @@ validate_attribute (location_t atloc, tree oper, tree attr)
 
   if (TYPE_P (oper))
     tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, oper);
-  else
+  else if (DECL_P (oper))
     tmpdecl = build_decl (atloc, TREE_CODE (oper), tmpid, TREE_TYPE (oper));
+  else if (EXPR_P (oper))
+    tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, TREE_TYPE (oper));
+  else
+    return false;
 
   /* Temporarily clear CURRENT_FUNCTION_DECL to make decl_attributes
      believe the DECL declared above is at file scope.  (See bug 87526.)  */
@@ -4043,7 +4084,7 @@ validate_attribute (location_t atloc, tree oper, tree attr)
   if (DECL_P (tmpdecl))
     {
       if (DECL_P (oper))
-	/* An alias cannot be a defintion so declare the symbol extern.  */
+	/* An alias cannot be a definition so declare the symbol extern.  */
 	DECL_EXTERNAL (tmpdecl) = true;
       /* Attribute visibility only applies to symbols visible from other
 	 translation units so make it "public."   */
@@ -4079,11 +4120,17 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
       do
 	{
 	  /* Determine the array element/member declaration from
-	     an ARRAY/COMPONENT_REF.  */
+	     a COMPONENT_REF and an INDIRECT_REF involving a refeence.  */
 	  STRIP_NOPS (t);
 	  tree_code code = TREE_CODE (t);
-	  if (code == ARRAY_REF)
-	    t = TREE_OPERAND (t, 0);
+	  if (code == INDIRECT_REF)
+	    {
+	      tree op0 = TREE_OPERAND (t, 0);
+	      if (TREE_CODE (TREE_TYPE (op0)) == REFERENCE_TYPE)
+		t = op0;
+	      else
+		break;
+	    }
 	  else if (code == COMPONENT_REF)
 	    t = TREE_OPERAND (t, 1);
 	  else
@@ -4134,7 +4181,8 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
 	}
       else
 	{
-	  atlist = TYPE_ATTRIBUTES (TREE_TYPE (expr));
+	  type = TREE_TYPE (expr);
+	  atlist = TYPE_ATTRIBUTES (type);
 	  done = true;
 	}
 
@@ -4210,9 +4258,10 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
 	      if (tree arg = TREE_VALUE (attr))
 		{
 		  arg = convert (TREE_VALUE (arg));
-		  if (expr && DECL_P (expr)
-		      && DECL_USER_ALIGN (expr)
-		      && tree_fits_uhwi_p (arg))
+		  if (!tree_fits_uhwi_p (arg))
+		    /* Invalid argument.  */;
+		  else if (expr && DECL_P (expr)
+			   && DECL_USER_ALIGN (expr))
 		    found_match = DECL_ALIGN_UNIT (expr) == tree_to_uhwi (arg);
 		  else if (type && TYPE_USER_ALIGN (type))
 		    found_match = TYPE_ALIGN_UNIT (type) == tree_to_uhwi (arg);
@@ -4249,13 +4298,7 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
 	    }
 	  else if (!strcmp ("vector_size", namestr))
 	    {
-	      if (!type)
-		continue;
-
-	      /* Determine the base type from arrays, pointers, and such.
-		 Fail if the base type is not a vector.  */
-	      type = type_for_vector_size (type);
-	      if (!VECTOR_TYPE_P (type))
+	      if (!type || !VECTOR_TYPE_P (type))
 		return false;
 
 	      if (tree arg = TREE_VALUE (attr))
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c669e49214f..6c24f2ff96a 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8552,9 +8552,9 @@ cp_parser_has_attribute_expression (cp_parser *parser)
   cp_parser_parse_definitely (parser);
 
   /* If the type-id production did not work out, then we must be
-     looking at the unary-expression production.  */
+     looking at an expression.  */
   if (!oper || oper == error_mark_node)
-    oper = cp_parser_unary_expression (parser);
+    oper = cp_parser_assignment_expression (parser);
 
   STRIP_ANY_LOCATION_WRAPPER (oper);
 
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 318f7e9784a..cfde248dd3d 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1247,14 +1247,18 @@ constant_alignment_word_strings (const_tree exp, HOST_WIDE_INT align)
   return align;
 }
 
-/* Default to natural alignment for vector types.  */
+/* Default to natural alignment for vector types, bounded by
+   MAX_OFILE_ALIGNMENT.  */
+
 HOST_WIDE_INT
 default_vector_alignment (const_tree type)
 {
-  HOST_WIDE_INT align = tree_to_shwi (TYPE_SIZE (type));
-  if (align > MAX_OFILE_ALIGNMENT)
-    align = MAX_OFILE_ALIGNMENT;
-  return align;
+  unsigned HOST_WIDE_INT align = MAX_OFILE_ALIGNMENT;
+  tree size = TYPE_SIZE (type);
+  if (tree_fits_uhwi_p (size))
+    align = tree_to_uhwi (size);
+
+  return align < MAX_OFILE_ALIGNMENT ? align : MAX_OFILE_ALIGNMENT;
 }
 
 /* The default implementation of
diff --git a/gcc/testsuite/c-c++-common/attributes-1.c b/gcc/testsuite/c-c++-common/attributes-1.c
index c4b232dad00..b73d31aa5e2 100644
--- a/gcc/testsuite/c-c++-common/attributes-1.c
+++ b/gcc/testsuite/c-c++-common/attributes-1.c
@@ -4,7 +4,7 @@
 void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,bar))); /* { dg-warning ".alloc_size. attribute argument 2 is invalid" } */
 void* my_realloc(void*, unsigned) __attribute__((alloc_size(bar))); /* { dg-warning ".alloc_size. attribute argument is invalid" } */
 
-typedef char vec __attribute__((vector_size(bar))); /* { dg-warning "ignored" } */
+typedef char vec __attribute__((vector_size(bar)));
 
 void f1(char*) __attribute__((nonnull(bar))); /* { dg-warning ".nonnull. attribute argument is invalid" } */
 
@@ -14,7 +14,7 @@ void foo(int);
 void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,foo))); /* { dg-warning ".alloc_size. attribute argument 2 has type .void\\\(int\\\)." } */
 void* my_realloc(void*, unsigned) __attribute__((alloc_size(foo))); /* { dg-warning ".alloc_size. attribute argument has type .void ?\\\(int\\\)" } */
 
-typedef char vec __attribute__((vector_size(foo))); /* { dg-warning "ignored" } */
+typedef char vec __attribute__((vector_size(foo))); /* { dg-error ".vector_size. attribute argument value .foo. is not an integer constant" } */
 
 void f1(char*) __attribute__((nonnull(foo))); /* { dg-warning ".nonnull. attribute argument has type .void ?\\\(int\\\)." } */
 void f2(char*) __attribute__((nonnull(1,foo))); /* { dg-warning ".nonnull. attribute argument 2 has type .void ?\\\(int\\\)." } */
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
index a0681fa6980..ec3127794b5 100644
--- a/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
@@ -3,7 +3,7 @@
    { dg-skip-if "No section attribute" { { hppa*-*-hpux* } && { ! lp64 } } }
    { dg-options "-Wall -ftrack-macro-expansion=0" }
    { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } }
-   { dg-additional-options "-DSKIP_ALIAS" { target *-*-darwin* } } 
+   { dg-additional-options "-DSKIP_ALIAS" { target *-*-darwin* } }
 */
 
 #define ATTR(...) __attribute__ ((__VA_ARGS__))
@@ -155,7 +155,8 @@ void test_packed (struct PackedMember *p)
   A (0, gpak[0].c, packed);
   A (0, gpak[1].s, packed);
   A (1, gpak->a, packed);
-  A (1, (*gpak).a[0], packed);
+  /* It's the array that's declared packed but not its elements.  */
+  A (0, (*gpak).a[0], packed);
 
   /* The following fails because in C it's represented as
        INDIRECT_REF (POINTER_PLUS (NOP_EXPR (ADDR_EXPR (gpak)), ...))
@@ -165,7 +166,8 @@ void test_packed (struct PackedMember *p)
   A (0, p->c, packed);
   A (0, p->s, packed);
   A (1, p->a, packed);
-  A (1, p->a[0], packed);
+  /* It's the array that's declared packed but not its elements.  */
+  A (0, p->a[0], packed);
   /* Similar to the comment above.
    A (1, *p->a, packed);  */
 }
@@ -218,13 +220,68 @@ void test_vector_size (void)
   A (1, iv16, vector_size (16));
   A (0, iv16, vector_size (32));
 
+  /* Verify that the attribute not detected on an array of vectors
+     but is detected on its elements.  */
+  typedef ATTR (vector_size (8)) float afv8_t[4];
+  A (0, afv8_t, vector_size);
+  A (0, afv8_t, vector_size (1));
+  A (0, afv8_t, vector_size (2));
+  A (0, afv8_t, vector_size (4));
+  A (0, afv8_t, vector_size (8));
+  A (0, afv8_t, vector_size (16));
+
+  A (1, __typeof__ ((*(afv8_t*)0)[0]), vector_size);
+  A (0, __typeof__ ((*(afv8_t*)0)[1]), vector_size (1));
+  A (0, __typeof__ ((*(afv8_t*)0)[2]), vector_size (2));
+  A (0, __typeof__ ((*(afv8_t*)0)[3]), vector_size (4));
+  A (1, __typeof__ ((*(afv8_t*)0)[0]), vector_size (8));
+  A (0, __typeof__ ((*(afv8_t*)0)[1]), vector_size (16));
+
+  A (1, __typeof__ (**(afv8_t*)0), vector_size);
+  A (0, __typeof__ (**(afv8_t*)0), vector_size (1));
+  A (0, __typeof__ (**(afv8_t*)0), vector_size (2));
+  A (0, __typeof__ (**(afv8_t*)0), vector_size (4));
+  A (1, __typeof__ (**(afv8_t*)0), vector_size (8));
+  A (0, __typeof__ (**(afv8_t*)0), vector_size (16));
+
   ATTR (vector_size (8)) float afv8[4];
-  A (1, afv8, vector_size);
+  A (0, afv8, vector_size);
   A (0, afv8, vector_size (1));
   A (0, afv8, vector_size (2));
   A (0, afv8, vector_size (4));
-  A (1, afv8, vector_size (8));
+  A (0, afv8, vector_size (8));
   A (0, afv8, vector_size (16));
+
+  A (1, afv8[0], vector_size);
+  A (0, afv8[1], vector_size (1));
+  A (0, afv8[2], vector_size (2));
+  A (0, afv8[3], vector_size (4));
+  A (1, afv8[0], vector_size (8));
+  A (0, afv8[1], vector_size (16));
+
+  A (1, *afv8, vector_size);
+  A (0, *afv8, vector_size (1));
+  A (0, *afv8, vector_size (2));
+  A (0, *afv8, vector_size (4));
+  A (1, *afv8, vector_size (8));
+  A (0, *afv8, vector_size (16));
+
+  /* sizeof (long double) is 12 on i386.  */
+  enum { VecSize = 8 * sizeof (long double) };
+  ATTR (vector_size (VecSize)) long double aldv[1][2][3];
+  A (0, aldv, vector_size);
+  A (0, aldv[0], vector_size);
+  A (0, aldv[0][0], vector_size);
+  A (1, aldv[0][0][0], vector_size);
+  A (0, aldv[0][0][1], vector_size (VecSize / 2));
+  A (1, aldv[0][0][2], vector_size (VecSize));
+
+  A (0, aldv[0][0][0][0], vector_size);
+
+  A (0, *aldv, vector_size);
+  A (0, **aldv, vector_size);
+  A (1, ***aldv, vector_size);
+  A (1, ***aldv, vector_size (VecSize));
 }
 
 
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-6.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-6.c
new file mode 100644
index 00000000000..89cf4f23d47
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-6.c
@@ -0,0 +1,114 @@
+/* PR c/88383 - ICE calling _builtin_has_attribute(r, aligned(N)))
+   on an overaligned reference r
+   PR c/89288 - ICE in tree_code_size, at tree.c:865
+   { dg-options "-Wall -ftrack-macro-expansion=0" }
+   { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } }  */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+#define A(expect, sym, attr)						\
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+typedef ATTR (aligned (8)) int Int8;
+
+/* The attribute applies to the array, not to the type of its elements.  */
+extern ATTR (aligned (8)) char i8arr[];
+
+/* The attribute applies to the pointer, not to the type it points to.  */
+extern ATTR (aligned (8)) int *ptr;
+extern Int8 *i8ptr;
+
+#if __cplusplus
+
+/* Similarly here, the attribute applies to the reference, not to its type.  */
+extern ATTR (aligned (8)) int &ref;
+extern Int8 &i8ref;
+
+#else
+
+/* Fake references in C.  */
+extern ATTR (aligned (8)) int ref;
+Int8 i8ref;
+
+#endif
+
+void test (void)
+{
+  /* Verify that the built-in detects the attribute on the array. */
+  A (1, i8arr, aligned);
+  A (0, i8arr, aligned (1));
+  A (0, i8arr, aligned (2));
+  A (0, i8arr, aligned (4));
+  A (1, i8arr, aligned (8));
+  A (0, i8arr, aligned (16));
+
+  A (0, i8arr + 1, aligned);
+  A (0, i8arr + 2, aligned (1));
+  A (0, i8arr + 3, aligned (8));
+
+  /* Verify the builtin detects the absence of the attribute on
+     the elements.  */
+  A (0, i8arr[0], aligned);
+  A (0, *i8arr,   aligned);
+
+  /* Verify that the built-in doesn't confuse the attribute on
+     the pointer type with that to the pointed to type.  This
+     also exercises PR c/89288.  */
+  A (0, (Int8*)0, aligned);
+  A (0, (int*)0,  aligned);
+  A (0, (void*)0, aligned);
+  A (0, 0,        aligned);
+
+  /* Verify that the built-in detects the attribute on the pointer
+     itself. */
+  A (1, ptr, aligned);
+  A (0, ptr, aligned (1));
+  A (0, ptr, aligned (2));
+  A (0, ptr, aligned (4));
+  A (1, ptr, aligned (8));
+  A (0, ptr, aligned (16));
+
+  A (0, ptr + 1, aligned);
+  A (0, ptr + 2, aligned (1));
+  A (0, ptr + 3, aligned (8));
+
+  /* The pointed to type is not declared with attribute aligned.  */
+  A (0, *ptr, aligned);
+  A (0, *ptr, aligned (1));
+  A (0, *ptr, aligned (2));
+  A (0, *ptr, aligned (4));
+  A (0, *ptr, aligned (8));
+  A (0, *ptr, aligned (16));
+
+  A (0, *ptr + 1, aligned);
+  A (0, *ptr + 2, aligned (1));
+  A (0, *ptr + 3, aligned (8));
+
+  /* Verify that the built-in correctly detects the attribute on
+     the type of the lvalue referenced by the pointer. */
+  A (0, i8ptr,     aligned);
+  A (0, i8ptr,     aligned (8));
+  A (0, i8ptr + 1, aligned);
+  A (0, i8ptr + 3, aligned (8));
+  A (1, *i8ptr,    aligned);
+  A (0, *i8ptr,    aligned (1));
+  A (0, *i8ptr,    aligned (2));
+  A (0, *i8ptr,    aligned (4));
+  A (1, *i8ptr,    aligned (8));
+  A (0, *i8ptr,    aligned (16));
+
+  /* The reference itself is declared aligned, even though the type
+     it refers to isn't.  But see PR c++/88362.  */
+  A (1, ref, aligned);
+  A (0, ref, aligned (1));
+  A (0, ref, aligned (2));
+  A (0, ref, aligned (4));
+  A (1, ref, aligned (8));
+  A (0, ref, aligned (16));
+
+  /* Also verify that assignment expressions are accepted.  */
+  A (0, ref = 1,  aligned);
+  A (0, ref += 2, aligned (1));
+  A (0, ref /= 3, aligned (8));
+
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-7.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-7.c
new file mode 100644
index 00000000000..6ea2e9e7192
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-7.c
@@ -0,0 +1,396 @@
+/* Verify that __builtin_has_attribute detects attributes aligned
+   and packed in various forms of array dereferencing and indirection
+   expressions correspondingly to __alignof__.
+   { dg-do compile }
+   { dg-options "-Wall -Wno-unused -ftrack-macro-expansion=0" } */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+#define ALIGN(N)  ATTR (aligned (N))
+
+#define Assert(expr) typedef int _Assert [1 - 2 * !(expr)]
+
+/* Verify that  __builtin_has_attribute (EXPR, align (ALIGN)) returns
+   the EXPECTed result.  When EXPECT is true, verify that the EXPression
+   has the expected ALIGNment.    */
+#define A3(expect, expr, align) do {					\
+    Assert (!expect || __alignof__ (expr) == align);			\
+    Assert (expect == __builtin_has_attribute (expr, aligned (align))); \
+  } while (0)
+
+#define A(expect, expr)							\
+  Assert (expect == __builtin_has_attribute (expr, aligned))		\
+
+enum { PA = __alignof__ (void*) };
+
+/* Define pointer to pointer types, with different alignments
+   at each level of indirection.  */
+typedef struct S8 { char a[8]; }   S8;
+typedef ALIGN (8)  S8              I8;
+typedef ALIGN (16) I8             *P16_I8;
+typedef            P16_I8         *P_P16_I8;
+typedef ALIGN (32) P_P16_I8       *P32_P_P16_I8;
+typedef            P32_P_P16_I8   *P_P32_P_P16_I8;
+typedef ALIGN (64) P_P32_P_P16_I8 *P64_P_P32_P_P16_I8;
+
+Assert ( 8 == __alignof__ (I8));
+Assert (16 == __alignof__ (P16_I8));
+Assert (PA == __alignof__ (P_P16_I8));
+Assert (32 == __alignof__ (P32_P_P16_I8));
+Assert (PA == __alignof__ (P_P32_P_P16_I8));
+Assert (64 == __alignof__ (P64_P_P32_P_P16_I8));
+
+
+/* Similar to the pointer of pointers above, define array of array
+   types, with different alignments at each level of indirection.  */
+typedef struct S64 { char a[64]; } S64;
+typedef ALIGN (64) S64             I64;
+typedef ALIGN (32) I64             A32_I64[3];
+typedef            A32_I64         A_A32_I64[5];
+typedef ALIGN (16) A_A32_I64       A16_A_A32_I64[7];
+typedef            A16_A_A32_I64   A_A16_A_A32_I64[11];
+typedef ALIGN (8)  A_A16_A_A32_I64 A8_A_A16_A_A32_I64[13];
+
+Assert (64 == __alignof__ (I64));
+Assert (32 == __alignof__ (A32_I64));
+/* With no explicit alignment, an array of overaligned elements
+   is considered to have the alignment of its elements.  */
+Assert (32 == __alignof__ (A_A32_I64));
+Assert (16 == __alignof__ (A16_A_A32_I64));
+Assert (16 == __alignof__ (A_A16_A_A32_I64));
+Assert ( 8 == __alignof__ (A8_A_A16_A_A32_I64));
+
+
+void test_arrays (void)
+{
+  /* Verify that the aligned attribute on each of the composite types
+     is detected corresponding to the result of __alignof__.  */
+  A (1, (*(A8_A_A16_A_A32_I64*)0));
+  A3 (1, (*(A8_A_A16_A_A32_I64*)0), 8);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 8);
+  /* GCC propagates the user-align bit from element types to their
+     arrays but it doesn't propagate the attribute itself.  The built-in
+     considers both the  bit and the attribute so it succeeds below even
+     though the referenced type isn't declared with the attribute.  */
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 8);
+  A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0], 16);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 32);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1], 8);
+  A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1], 16);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1], 32);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 16);
+  A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 32);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 64);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 16);
+  A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 32);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 64);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 32);
+  A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 64);
+  A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 128);
+
+  A8_A_A16_A_A32_I64 a;
+  A3 (0, a[0], 8);
+  A3 (1, a[0], 16);
+  A3 (0, a[0], 32);
+  A3 (0, a[0][1], 8);
+  A3 (1, a[0][1], 16);
+  A3 (0, a[0][1], 32);
+  A3 (0, a[0][1][2], 16);
+  A3 (1, a[0][1][2], 32);
+  A3 (0, a[0][1][2], 64);
+  A3 (0, a[0][1][2][3], 16);
+  A3 (1, a[0][1][2][3], 32);
+  A3 (0, a[0][1][2][3], 64);
+  A3 (0, a[0][1][2][3][4], 32);
+  A3 (1, a[0][1][2][3][4], 64);
+  A3 (0, a[0][1][2][3][4], 128);
+}
+
+void test_pointers (void)
+{
+  /* Verify that the aligned attribute on each of the composite pointer
+     types is detected corresponding to the result of __alignof__.  */
+  A (1, I8);
+  A3 (0, I8, 4);
+  A3 (1, I8, 8);
+
+  A (1, P16_I8);
+  A3 (0, P16_I8, 8);
+  A3 (1, P16_I8, 16);
+
+  A (0, P_P16_I8);
+  A3 (0, P_P16_I8, 8);
+  A3 (0, P_P16_I8, 16);
+
+  A (1, P32_P_P16_I8);
+  A3 (0, P32_P_P16_I8, 8);
+  A3 (0, P32_P_P16_I8, 16);
+  A3 (1, P32_P_P16_I8, 32);
+
+  A (0, P_P32_P_P16_I8);
+
+  A (1, P64_P_P32_P_P16_I8);
+  A3 (0, P64_P_P32_P_P16_I8, 8);
+  A3 (0, P64_P_P32_P_P16_I8, 16);
+  A3 (0, P64_P_P32_P_P16_I8, 32);
+  A3 (1, P64_P_P32_P_P16_I8, 64);
+
+
+  /* Verify that the attribute on each of the composite types is detected
+     in the type of each of the indirection expressions.  */
+  A (1, *(P16_I8)0);
+  A3 (1, *(P16_I8)0, 8);
+  A3 (0, *(P16_I8)0, 16);
+
+  A (1, *(P_P16_I8)0);
+  A3 (0, *(P_P16_I8)0, 8);
+  A3 (1, *(P_P16_I8)0, 16);
+
+  A (0, *(P32_P_P16_I8)0);
+  A3 (0, *(P32_P_P16_I8)0, 8);
+  A3 (0, *(P32_P_P16_I8)0, 16);
+  A3 (0, *(P32_P_P16_I8)0, 32);
+
+  A (1, *(P_P32_P_P16_I8)0);
+  A3 (1, *(P_P32_P_P16_I8)0, 32);
+
+  A (0, *(P64_P_P32_P_P16_I8)0);
+
+  /* Verify that the attribute on each of the composite types is detected
+     in the type of each of the subscipting expressions.  */
+  A (1, ((P16_I8)0)[0]);
+  A3 (1, ((P16_I8)0)[1], 8);
+  A3 (0, ((P16_I8)0)[2], 16);
+
+  A (1, ((P_P16_I8)0)[3]);
+  A3 (0, ((P_P16_I8)0)[4], 8);
+  A3 (1, ((P_P16_I8)0)[5], 16);
+
+  A (0, ((P32_P_P16_I8)0)[6]);
+  A3 (0, ((P32_P_P16_I8)0)[7], 8);
+  A3 (0, ((P32_P_P16_I8)0)[8], 16);
+  A3 (0, ((P32_P_P16_I8)0)[9], 32);
+
+  A (1, ((P_P32_P_P16_I8)0)[10]);
+  A3 (1, ((P_P32_P_P16_I8)0)[11], 32);
+
+  A (0, ((P64_P_P32_P_P16_I8)0)[12]);
+
+
+  /* Verify that the attribute on each of the composite types is detected
+     in the type of each of the subscipting expression involving variables.  */
+
+  I8                   i8;
+  P16_I8               p16_i8 = &i8;
+  P_P16_I8             p_p16_i8 = &p16_i8;
+  P32_P_P16_I8         p32_p_p16_i8 = &p_p16_i8;
+  P_P32_P_P16_I8       p_p32_p_p16_i8 = &p32_p_p16_i8;
+  P64_P_P32_P_P16_I8   p64_p_p32_p_p16_i8 = &p_p32_p_p16_i8;
+
+  A (1, p16_i8[0]);
+  A3 (1, p16_i8[1], 8);
+  A3 (0, p16_i8[2], 16);
+
+  A (1, p_p16_i8[3]);
+  A3 (0, p_p16_i8[4], 8);
+  A3 (1, p_p16_i8[5], 16);
+
+  A (0, p32_p_p16_i8[6]);
+  A3 (0, p32_p_p16_i8[7], 8);
+  A3 (0, p32_p_p16_i8[8], 16);
+  A3 (0, p32_p_p16_i8[9], 32);
+
+  A (1, p_p32_p_p16_i8[10]);
+  A3 (1, p_p32_p_p16_i8[11], 32);
+
+
+  A (1, p_p16_i8[0][1]);
+  A3 (1, p_p16_i8[1][2], 8);
+  A3 (0, p_p16_i8[2][3], 16);
+
+
+  A (0, p64_p_p32_p_p16_i8[0]);
+
+  A (1, p64_p_p32_p_p16_i8[0][1]);
+  A3 (0, p64_p_p32_p_p16_i8[0][2], 16);
+  A3 (1, p64_p_p32_p_p16_i8[0][3], 32);
+  A3 (0, p64_p_p32_p_p16_i8[0][4], 64);
+
+  A (0, p64_p_p32_p_p16_i8[0][1][2]);
+
+  A (1, p64_p_p32_p_p16_i8[0][1][2][3]);
+  A3 (0, p64_p_p32_p_p16_i8[0][1][2][4], 8);
+  A3 (1, p64_p_p32_p_p16_i8[0][1][2][4], 16);
+  A3 (0, p64_p_p32_p_p16_i8[0][1][2][4], 32);
+
+  A (1, p64_p_p32_p_p16_i8[0][1][2][3][4]);
+  A3 (1, p64_p_p32_p_p16_i8[0][1][2][3][5], 8);
+  A3 (0, p64_p_p32_p_p16_i8[0][1][2][4][6], 16);
+
+
+  /* Same as above but using the indirection expression.  */
+  A (0, *p64_p_p32_p_p16_i8);
+
+  A (1, **p64_p_p32_p_p16_i8);
+  A3 (0, **p64_p_p32_p_p16_i8, 16);
+  A3 (1, **p64_p_p32_p_p16_i8, 32);
+  A3 (0, **p64_p_p32_p_p16_i8, 64);
+
+  A (0, ***p64_p_p32_p_p16_i8);
+
+  A (1, ****p64_p_p32_p_p16_i8);
+  A3 (0, ****p64_p_p32_p_p16_i8, 8);
+  A3 (1, ****p64_p_p32_p_p16_i8, 16);
+  A3 (0, ****p64_p_p32_p_p16_i8, 32);
+
+  A (1, *****p64_p_p32_p_p16_i8);
+  A3 (1, *****p64_p_p32_p_p16_i8, 8);
+  A3 (0, *****p64_p_p32_p_p16_i8, 16);
+}
+
+
+S8 f_S8 (void);
+I8 f_I8 (void);
+P16_I8 f_P16_I8 (void);
+P_P16_I8 f_P_P16_I8 (void);
+P32_P_P16_I8 f_P32_P_P16_I8 (void);
+P_P32_P_P16_I8 f_P_P32_P_P16_I8 (void);
+P64_P_P32_P_P16_I8 f_P64_P_P32_P_P16_I8 (void);
+
+void test_function_call (void)
+{
+  /* Verify that the aligned attribute on each of the composite pointer
+     types returned by the functions is detected corresponding to
+     the result of __alignof__.  */
+
+  A (0, f_S8 ());
+
+  A (1, f_I8 ());
+  A3 (1, f_I8 (), 8);
+  A3 (0, f_I8 (), 16);
+
+  A (1, f_P16_I8 ());
+  A3 (0, f_P16_I8 (), 8);
+  A3 (1, f_P16_I8 (), 16);
+  A3 (0, f_P16_I8 (), 32);
+
+  A (1, *f_P16_I8 ());
+  A3 (1, *f_P16_I8 (), 8);
+  A3 (0, *f_P16_I8 (), 16);
+
+  A (0, f_P_P16_I8 ());
+
+  A (1, *f_P_P16_I8 ());
+  A3 (0, *f_P_P16_I8 (), 8);
+  A3 (1, *f_P_P16_I8 (), 16);
+  A3 (0, *f_P_P16_I8 (), 32);
+
+  A (1, **f_P_P16_I8 ());
+  A3 (1, **f_P_P16_I8 (), 8);
+  A3 (0, **f_P_P16_I8 (), 16);
+  A3 (0, **f_P_P16_I8 (), 32);
+}
+
+
+void test_compound_literal (void)
+{
+  A (0, (S8){ });
+
+  A (1, (I8){ });
+  A3 (1, (I8){ }, 8);
+  A3 (0, (I8){ }, 16);
+
+  A (1, (I64){ });
+  A3 (0, (I64){ }, 8);
+  A3 (0, (I64){ }, 16);
+  A3 (0, (I64){ }, 32);
+  A3 (1, (I64){ }, 64);
+
+  A (1, (A32_I64){ 0 });
+  A3 (0, (A32_I64){ 0 }, 8);
+  A3 (0, (A32_I64){ 0 }, 16);
+  A3 (1, (A32_I64){ 0 }, 32);
+  A3 (0, (A32_I64){ 0 }, 64);
+
+  A (1, ((A32_I64){ 0 })[0]);
+  A3 (0, ((A32_I64){ 0 })[0], 8);
+  A3 (0, ((A32_I64){ 0 })[0], 16);
+  A3 (0, ((A32_I64){ 0 })[0], 32);
+  A3 (1, ((A32_I64){ 0 })[0], 64);
+}
+
+
+void test_ternary_expression (int i)
+{
+  A (0, (0 ? (S8){ } : (S8){ }));
+
+  A (1, (1 ? (I8){ } : (I8){ }));
+  A3 (1, (2 ? (I8){ } : (I8){ }), 8);
+  A3 (0, (3 ? (I8){ } : (I8){ }), 16);
+
+  A (1, (4 ? (I64){ } : (I64){ }));
+  A3 (0, (5 ? (I64){ } : (I64){ }), 8);
+  A3 (0, (6 ? (I64){ } : (I64){ }), 16);
+  A3 (0, (7 ? (I64){ } : (I64){ }), 32);
+  A3 (1, (8 ? (I64){ } : (I64){ }), 64);
+
+#if !__cplusplus
+  /* Suppress -Wc++-compat warning: converting an array compound literal
+     to a pointer is ill-formed in C++  */
+# pragma GCC diagnostic ignored "-Wc++-compat"
+
+  A (0, (9 ? (A32_I64){ } : (A32_I64){ })); 
+  A3 (0, (i ? (A32_I64){ } : (A32_I64){ }), 8);
+  A3 (0, (i++ ? (A32_I64){ } : (A32_I64){ }), 16);
+  A3 (0, (++i ? (A32_I64){ } : (A32_I64){ }), 32);
+  A3 (0, (!i ? (A32_I64){ } : (A32_I64){ }), 64);
+
+  A (1, (0 ? (A32_I64){ } : (A32_I64){ })[0]);
+  A3 (0, (1 ? (A32_I64){ } : (A32_I64){ })[1], 8);
+  A3 (0, (2 ? (A32_I64){ } : (A32_I64){ })[2], 16);
+  A3 (0, (3 ? (A32_I64){ } : (A32_I64){ })[3], 32);
+  A3 (1, (3 ? (A32_I64){ } : (A32_I64){ })[i], 64);
+#endif
+}
+
+
+void test_comma_expression (int i)
+{
+#if __cplusplus
+  /* In C++, the type of the comma expressions whose operand is an array
+     is the array itself with any attributes it was defined with.  */
+# define R 1
+#else
+  /* In C, the type of the comma expressions whose operand is an array
+     is a pointer type that does not include any attributes the array
+     was defined with.  */
+# define R 0
+/* Suppress -Wc++-compat warning: converting an array compound literal
+   to a pointer is ill-formed in C++
+   G++ accepts the conversion in unevaluated contexts without a warning.  */
+# pragma GCC diagnostic ignored "-Wc++-compat"
+#endif
+
+  A (0, (0, (S8){ }));
+
+  A (1, (0, (I8){ }));
+  A3 (1, (1, (I8){ }), 8);
+  A3 (0, (2, (I8){ }), 16);
+
+  A (1, (3, (I64){ }));
+  A3 (0, (4, (I64){ }), 8);
+  A3 (0, (5, (I64){ }), 16);
+  A3 (0, (6, (I64){ }), 32);
+  A3 (1, (7, (I64){ }), 64);
+
+  A (R, (8, (A32_I64){ }));
+  A3 (0, (9, (A32_I64){ }), 8);
+  A3 (0, ((void)0, (A32_I64){ }), 16);
+  A3 (R, ((I64){ },(A32_I64){ }), 32);
+  A3 (0, (0, (A32_I64){ }), 64);
+
+  A (1, (1, ((A32_I64){ })[0]));
+  A3 (0, (2, ((A32_I64){ })[0]), 8);
+  A3 (0, (i++, ((A32_I64){ })[0]), 16);
+  A3 (0, (++i, ((A32_I64){ })[0]), 32);
+  A3 (1, (i = 0, ((A32_I64){ })[0]), 64);
+}
diff --git a/gcc/testsuite/gcc.dg/attr-vector_size.c b/gcc/testsuite/gcc.dg/attr-vector_size.c
new file mode 100644
index 00000000000..00be26accd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-vector_size.c
@@ -0,0 +1,69 @@
+/* PR middle-end/89797 - ICE on a vector_size (1LU << 33) int variable
+   PR c/89798 - excessive vector_size silently accepted and truncated
+   { dg-do compile { target int32plus } }
+   { dg-options "-Wall -Wno-unused" } */
+
+#define ASSERT(e)    _Static_assert (e, #e)
+#define VEC(N)       __attribute__ ((vector_size (N)))
+#define POW2(N)      (1LLU << N)
+#define CAT(a, b)    a ## b
+#define CONCAT(a, b) CAT (a, b)
+
+#define DEFVEC(storage, N)				\
+  typedef VEC (POW2 (N)) char CONCAT (Vec, N);		\
+  storage CONCAT (Vec, N) CONCAT (v, N);		\
+  ASSERT (sizeof (CONCAT (Vec, N)) == POW2 (N));	\
+  ASSERT (sizeof (CONCAT (v, N)) == POW2 (N))
+
+DEFVEC (extern, 27);
+DEFVEC (extern, 28);
+DEFVEC (extern, 29);
+DEFVEC (extern, 30);
+
+#if __SIZEOF_SIZE_T__ > 4
+
+DEFVEC (extern, 31);
+DEFVEC (extern, 32);
+DEFVEC (extern, 33);
+DEFVEC (extern, 34);
+DEFVEC (extern, 60);
+DEFVEC (extern, 61);
+DEFVEC (extern, 62);
+
+VEC (POW2 (63)) char v63;     /* { dg-error  "'vector_size' attribute argument value '9223372036854775808' exceeds 9223372036854775807" "LP64" { target lp64 } } */
+
+#else
+
+VEC (POW2 (31)) char v31;     /* { dg-error  "'vector_size' attribute argument value '2147483648' exceeds 2147483647" "ILP32" { target ilp32 } } */
+
+VEC (POW2 (32)) char v32;     /* { dg-error  "'vector_size' attribute argument value '4294967296' exceeds 2147483647" "ILP32" { target ilp32 } } */
+
+#endif
+
+void test_local_scope (void)
+{
+  DEFVEC (auto, 27);
+  DEFVEC (auto, 28);
+  DEFVEC (auto, 29);
+  DEFVEC (auto, 30);
+
+#if __SIZEOF_SIZE_T__ > 4
+
+  DEFVEC (auto, 31);
+  DEFVEC (auto, 32);
+  DEFVEC (auto, 33);
+  DEFVEC (auto, 34);
+  DEFVEC (auto, 60);
+  DEFVEC (auto, 61);
+  DEFVEC (auto, 62);
+
+  VEC (POW2 (63)) char v63;   /* { dg-error  "'vector_size' attribute argument value '9223372036854775808' exceeds 9223372036854775807" "LP64" { target lp64 } } */
+
+#else
+
+  VEC (POW2 (31)) char v31;   /* { dg-error  "'vector_size' attribute argument value '2147483648' exceeds 2147483647" "ILP32" { target ilp32 } } */
+
+  VEC (POW2 (32)) char v32;   /* { dg-error  "'vector_size' attribute argument value '4294967296' exceeds 2147483647" "ILP32" { target ilp32 } } */
+
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/pr25559.c b/gcc/testsuite/gcc.dg/pr25559.c
index 7879a1558b6..a8bce657b1c 100644
--- a/gcc/testsuite/gcc.dg/pr25559.c
+++ b/gcc/testsuite/gcc.dg/pr25559.c
@@ -2,7 +2,7 @@
 /* { dg-do compile } */
 
 #define vs(n) __attribute__((vector_size (n)))
-int vs (-1) a;			/* { dg-warning "attribute ignored" } */
+int vs (-1) a;			/* { dg-error ".vector_size. attribute argument value '-1' is negative" } */
 int vs (0) b;			/* { dg-error "zero vector size" } */
 int vs (1) c;			/* { dg-error "multiple of component size" } */
 int vs (sizeof (int) / 2) d;	/* { dg-error "multiple of component size" } */
diff --git a/gcc/tree.h b/gcc/tree.h
index 0e8e8dff876..94a810694a5 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3741,7 +3741,7 @@ TYPE_VECTOR_SUBPARTS (const_tree node)
       return res;
     }
   else
-    return 1 << precision;
+    return (unsigned HOST_WIDE_INT)1 << precision;
 }
 
 /* Set the number of elements in VECTOR_TYPE NODE to SUBPARTS, which must

Reply via email to