diff mbox

c++/58109 - alignas() fails to compile with constant expression

Message ID 56A0127C.6020009@gmail.com
State New
Headers show

Commit Message

Martin Sebor Jan. 20, 2016, 11:04 p.m. UTC
> Right.  The problem is this code in is_late_template_attribute:
>
>>       /* If the first attribute argument is an identifier, only consider
>>          second and following arguments.  Attributes like mode, format,
>>          cleanup and several target specific attributes aren't late
>>          just because they have an IDENTIFIER_NODE as first argument.  */
>>       if (arg == args && identifier_p (t))
>>         continue;
>
> It shouldn't skip an initial identifier if !attribute_takes_identifier_p.

That seems backwards. I expected attribute_takes_identifier_p()
to return true for attribute aligned since the attribute does
take one.

In any case, I changed the patch as you suggest and retested it
on x86_64.  I saw the email about stage 3 having ended but I'm
not sure it applies to changes that are still in progress.

Martin

Comments

Jason Merrill Jan. 22, 2016, 8:41 p.m. UTC | #1
On 01/20/2016 06:04 PM, Martin Sebor wrote:
>> Right.  The problem is this code in is_late_template_attribute:
>>
>>>       /* If the first attribute argument is an identifier, only consider
>>>          second and following arguments.  Attributes like mode, format,
>>>          cleanup and several target specific attributes aren't late
>>>          just because they have an IDENTIFIER_NODE as first
>>> argument.  */
>>>       if (arg == args && identifier_p (t))
>>>         continue;
>>
>> It shouldn't skip an initial identifier if !attribute_takes_identifier_p.
>
> That seems backwards. I expected attribute_takes_identifier_p()
> to return true for attribute aligned since the attribute does
> take one.

There are some attributes (mode, format, cleanup) that have magic 
handling of identifiers; aligned treats its argument as an expression 
whether or not that expression takes the form of an identifier.

> In any case, I changed the patch as you suggest and retested it
> on x86_64.  I saw the email about stage 3 having ended but I'm
> not sure it applies to changes that are still in progress.

I wouldn't think so; certainly not for something this simple.  The patch 
is OK.

Jason
diff mbox

Patch

gcc/testsuite/ChangeLog:
2016-01-20  Martin Sebor  <msebor@redhat.com>

	PR c++/58109
	PR c++/69022
	* g++.dg/cpp0x/alignas5.C: New test.
	* g++.dg/ext/vector29.C: Same.

gcc/cp/ChangeLog:
2016-01-20  Martin Sebor  <msebor@redhat.com>

	PR c++/58109
	PR c++/69022
	* decl2.c (is_late_template_attribute): Handle dependent argument
	to attribute align and attribute vector_size.

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a7212ca0..7d68961 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1193,7 +1193,8 @@  is_late_template_attribute (tree attr, tree decl)
 	 second and following arguments.  Attributes like mode, format,
 	 cleanup and several target specific attributes aren't late
 	 just because they have an IDENTIFIER_NODE as first argument.  */
-      if (arg == args && identifier_p (t))
+      if (arg == args && attribute_takes_identifier_p (name)
+	  && identifier_p (t))
 	continue;
 
       if (value_dependent_expression_p (t)
diff --git a/gcc/testsuite/g++.dg/cpp0x/alignas5.C b/gcc/testsuite/g++.dg/cpp0x/alignas5.C
new file mode 100644
index 0000000..2dcc41f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alignas5.C
@@ -0,0 +1,45 @@ 
+// PR c++/58109  - alignas() fails to compile with constant expression
+// { dg-do compile }
+
+template <typename T>
+struct Base {
+  static const int Align = sizeof (T);
+};
+
+// Never instantiated.
+template <typename T>
+struct Derived: Base<T>
+{
+#if __cplusplus >= 201102L
+  // This is the meat of the (simplified) regression test for c++/58109.
+  using B = Base<T>;
+  using B::Align;
+
+  alignas (Align) char a [1];
+  alignas (Align) T b [1];
+#else
+  // Fake the test for C++ 98.
+#  define Align Base<T>::Align
+#endif
+
+  char __attribute__ ((aligned (Align))) c [1];
+  T __attribute__ ((aligned (Align))) d [1];
+};
+
+// Instantiated to verify that the code is accepted even when instantiated.
+template <typename T>
+struct InstDerived: Base<T>
+{
+#if __cplusplus >= 201102L
+  using B = Base<T>;
+  using B::Align;
+
+  alignas (Align) char a [1];
+  alignas (Align) T b [1];
+#endif
+
+  char __attribute__ ((aligned (Align))) c [1];
+  T __attribute__ ((aligned (Align))) d [1];
+};
+
+InstDerived<int> dx;
diff --git a/gcc/testsuite/g++.dg/ext/vector29.C b/gcc/testsuite/g++.dg/ext/vector29.C
new file mode 100644
index 0000000..4a13009
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/vector29.C
@@ -0,0 +1,53 @@ 
+// PR c++/69022 - attribute vector_size ignored with dependent bytes
+// { dg-do compile }
+
+template <int N>
+struct A { static const int X = N; };
+
+#if __cplusplus >= 201202L
+#  define ASSERT(e) static_assert (e, #e)
+#else
+#  define ASSERT(e)   \
+  do { struct S { bool: !!(e); } asrt; (void)&asrt; } while (0)
+#endif
+
+template <class T, int N>
+struct B: A<N>
+{
+#if __cplusplus >= 201202L
+  using A<N>::X;
+#  define VecSize X
+#else
+#  define VecSize A<N>::X
+#endif
+
+    static void foo ()
+    {
+        char a __attribute__ ((vector_size (N)));
+        ASSERT (sizeof a == N);
+
+        T b __attribute__ ((vector_size (N)));
+        ASSERT (sizeof b == N);
+    }
+
+    static void bar ()
+    {
+        char c1 __attribute__ ((vector_size (VecSize)));
+        ASSERT (sizeof c1 == VecSize);
+
+        char c2 __attribute__ ((vector_size (A<N>::X)));
+        ASSERT (sizeof c2 == A<N>::X);
+
+        T d1 __attribute__ ((vector_size (VecSize)));
+        ASSERT (sizeof d1 == VecSize);
+
+        T d2 __attribute__ ((vector_size (A<N>::X)));
+        ASSERT (sizeof d2 == A<N>::X);
+    }
+};
+
+void bar ()
+{
+    B<int, 16>::foo ();
+    B<int, 16>::bar ();
+}