Search code examples
c++arraysalignmentlanguage-lawyeralignas

Valid positions of `alignas` inside a plain array definition


I'd like to understand the validity of different alignas specifier position within a plain array definition:

constexpr std::size_t Required=16;

alignas(Required) int iarr1[10]; // 1
int alignas(Required) iarr2[10]; // 2
int iarr3 alignas(Required) [10]; // 3
int iarr4 [10] alignas(Required); // 4

2 is ignored by gcc with a warning.
2 and 4 give plain errors with clang LIVE.

This answer explains why 1 is correct, but does not cover the other cases and I'd like to understand what other forms might be valid.

According to me:

  • 2 may be wrong because alignas will be parsed as part of the type (int) declaration and it cannot apply to types as clang and gcc report (thus, acceptance by msvc would be a bug).
  • 3 may be correct because its a simple-declaration; int is forming de decl-specifier-seq while iarr3 alignas(Required) [10] seems a valid noptr-declarator consisting of a noptr-declarator+attribute-specifier which itself is a noptr-declarator followed by [] forming again a noptr-declarator which, ultimately can be interpreted as an * init-declarator-list*.
  • 4 may be correct following the same line of reasoning (switching [] and the attribute-specifier still form a noptr-declarator); yet it is rejected by clang.

What analyses are (in)correct and why?


For the record, the running snippet linked above:

#include <iostream>

int main() {
    constexpr std::size_t Required = 16;

    alignas(Required) int iarr1[10];

#if defined(__GNUG__)
    int iarr2[10];
#if defined(__clang__)
    std::cout << "clang rejects int alignas(Required) iarr2[10];\n";
#else
    std::cout << "gcc ignore int alignas(Required) iarr2[10]; with warning\n";
#endif
#else
    int alignas(Required) iarr2[10];
#endif

    int iarr3 alignas(Required)[10];

#ifndef __clang__
    int iarr4[10] alignas(Required);
#else
    std::cout << "clang rejects int iarr4[10] alignas(Required);\n";
    int iarr4[10];
#endif

    std::cout << iarr1 << '\n';
    std::cout << iarr2 << '\n';
    std::cout << iarr3 << '\n';
    std::cout << iarr4 << '\n';
}

Solution

  • alignas can only be applied to variables, non-static data members, and classes ([dcl.align]/1, [dcl.attr.grammar]/5).

    In the example you give:

    Thus, 1 and 3 are well-formed, while 2 and 4 are ill-formed.