| Document #: | P4192R0 [Latest] [Status] |
| Date: | 2026-04-20 |
| Project: | Programming Language C++ |
| Audience: |
Core Working Group |
| Reply-to: |
Vlad Serebrennikov <serebrennikov.vladislav@gmail.com> |
There are multiple open Core issues against 6.8.3 [basic.align] (1211, 2840) and 9.13.2 [dcl.align] (1617, 2223, 3024). This proposal aims to improve the specification of the aforementined subclauses, resolving at least some of the open issues.
R0:
GCC accepts a defining declaration without an alignment-specifier that happens to have the same alignment as specified in other declarations (in violation of [dcl.align]/6) (Compiler Explorer):
struct alignas(4) A;
struct A { alignas(4) int i; }; // GCC accepts, Clang, EDG, and MSVC rejectClang considers alignas(0)
to have no effect for the purposes of [dcl.align]/5, yet
considers it to have an effect for the purposes of [dcl.align]/6 (Compiler Explorer):
struct alignas(0) B1;
struct B1 {}; // Clang rejects, GCC, EDG, and MSVC accept
struct alignas(0) B2;
struct alignas(0) B2 {}; // all acceptClang rejects alignment-specifiers on non-static data members of reference type, EDG accepts only if the specified alignment is stricter than the alignment in the absence of alignment-specifier, GCC and MSVC accept any alignment-specifier (even though non-static data members that are references are not variables) (CWG3024) (Compiler Explorer):
struct C1 { alignas(2) const int& r1 = 7; }; // Clang and EDG reject, GCC and MSVC accept
static_assert(alignof(C1) == 8); // all accept
struct C2 { alignas(16) const int& r2 = 7; }; // Clang rejects, GCC, EDG, and MSVC accept
static_assert(alignof(C2) == 16); // all acceptClang and GCC prioritize
#pragma pack
over alignment-specifiers
of non-static data members and their types, MSVC does the opposite,
while EDG prioritize
#pragma pack
over alignment-specifier
of types but not of non-static data members (Compiler Explorer):
struct alignas(8) D1 { int m; };
#pragma pack(2)
struct D2 {
char m1;
D1 m2;
char m3;
alignas(8) int m4;
};
static_assert(alignof(D2) == 2); // Clang and GCC accept
static_assert(alignof(D2) == 8); // EDG, MSVC, and Clang in MSVC compatibility mode accept
static_assert(sizeof(D2) == 12); // Clang and GCC accept
static_assert(sizeof(D2) == 24); // EDG accepts; m4 is at offset of 16
static_assert(sizeof(D2) == 32); // MSVC and Clang in MSVC compatibility mode acceptT is
obtained”. Maybe it’s worth harmonizing “proper alignment”,
“sufficiently aligned”, and “meets alignment requirements” across the
Standard.long double,
which is a fundamental type, is a valid alignmentalignof
operator without leaving as much as a note in [expr.align].This section is preliminary in the light of implementation divergence discussed above.
alignof
expression reports alignment (which is what all implementations do in
the presence of extensions).alignas
and represented as an integral value.To enable
#pragma pack
as an extension that a conforming implementation can have ([intro.compliance]/11):
This section is preliminary in the light of implementation divergence discussed above.
1
Object types have alignment requirements (6.9.2 [basic.fundamental], 6.9.4 [basic.compound]) which place restrictions on the addresses at which regions of storage an object of that type may be allocated.An alignment is animplementation-definedinteger valuerepresenting the number of bytes between successive addresses atwhich describes restrictions on the address of the first byte of a region of storage that a given object canbe allocatedoccupy. Objects and object types have alignment requirement (6.9.2 [basic.fundamental], 6.9.4 [basic.compound]), which is a value of typestd::size_t. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment-specifier (9.13.2 [dcl.align]).1a Alignment requirement of an entity influences its alignment in an implementation-defined manner. Consequently, it is implementation-defined whether a given region of storage meets alignment requirement of a given object.
[Note:
Attempting to create an object (6.8.2 [intro.object]) in storage that does not meet the alignment requirements of the object’s type is undefined behavior.The lifetime of an object cannot start if its storage is not sufficiently aligned (6.8.4 [basic.life]), including cases when the object is created by a new-expression whose allocation function is a non-allocating form (7.6.2.8 [expr.new], 17.6.3.4 [new.delete.placement]). — end note ]2 A fundamental alignment requirement is
represented byan alignment requirement that is less than or equal toalignof(std::max_align_t).[Note:
alignof(std::max_align_t)is the greatest alignment requirement supported by the implementation in all contexts, which is equal to(17.2 [support.types]). — end note ]alignof(std::max_align_t)2a The alignment required for a type may be different when it is used as the type of a complete object and when it is used as the type of a subobject.
[Example:struct B { long double d; }; struct D : virtual B { char c; };When
Dis the type of a complete object, it will have a subobject of typeB, so it must be aligned appropriately for along double. IfDappears as a subobject of another object that also hasBas a virtual base class, theBsubobject might be part of a different subobject, reducing the alignment requirements on theDsubobject. — end example ]
The result of thealignofoperator reflects the alignment requirement of the type in the complete-object case.3 An extended alignment requirement is
represented byan alignment requirement greater thanalignof(std::max_align_t). It is implementation-defined whether any extended alignments are supported and the contexts in which they are supported (9.13.2 [dcl.align]). A type having an extended alignment requirement is an over-aligned type.[Note: Every over-aligned type is
or contains a class type to which extended alignment applies (possibly through a non-static data member)either specified to have an extended alignment requirement (9.13.2 [dcl.align]), or has a subobject S of type T, where at least one of S or T is specified to have an extended alignment requirement. — end note ]A new-extended alignment is
represented byan alignment requirement greater than__STDCPP_DEFAULT_NEW_ALIGNMENT__(15.12 [cpp.predefined]).4
Alignments are represented as values of the typeEvery alignmentstd::size_t. Valid alignments include only those values returned by an alignof expression for the fundamental types plus an additional implementation-defined set of values, which may be empty.valuerequirement shall be a non-negative integral power of two., and shall be in one of the following sets of values:
- (4.1) values returned by an
alignofexpression whose type-id designates one of the fundamental types, or- (4.2) an implementation-defined set of values.
5 Alignments have an order from weaker to stronger or stricter alignments. Stricter alignments have larger alignment values. An address that satisfies an alignment requirement also satisfies any weaker
validalignment requirement.6 The alignment requirement of a complete type can be queried using an
alignofexpression (7.6.2.6 [expr.alignof]). Furthermore, the narrow character types (6.9.2 [basic.fundamental]) shall have the weakest alignment requirement.[Note: The type
unsigned charcan be used as the element type of an array providing aligned storage (9.13.2 [dcl.align]). — end note ]7 Comparing alignments is meaningful and provides the obvious results:
- (7.1) Two alignments are equal when their numeric values are equal.
- (7.2) Two alignments are different when their numeric values are not equal.
- (7.3) When an alignment is larger than another it represents a stricter alignment.
[Note: The runtime pointer alignment function (20.2.5 [ptr.align]) can be used to obtain an aligned pointer within a buffer; an alignment-specifier (9.13.2 [dcl.align]) can be used to align storage explicitly. — end note ]
9
If a request for a specific extended alignment in a specific context is not supported by an implementation, the program is ill-formed.
1 An
alignofexpression yields the alignment that a hypothetical complete object of its operand type would have. The operand shall be a type-id representing a complete object type, or an array thereof, or a reference to one of those types.[Note: Alignment can differ between a complete object and a subobject of the same type (6.8.3 [basic.align]). — end note ]
2 The result is a prvalue of type
std::size_t.[Note: An
alignofexpression is an integral constant expression ([expr.const.const]). The typedef-namestd::size_tis declared in the standard header<cstddef>(17.2.1 [cstddef.syn], 17.2.4 [support.types.layout]). — end note ]3 When
alignofis applied to a reference type, the result is the alignment of the referenced type. Whenalignofis applied to an array type, the result is the alignment of the element type.
Move the definition of alignment-specifier from paragraph 1 to the beginning of 9.13.2 [dcl.align]:
1 Attributes and annotations specify additional information for various source constructs such as types, variables, names, contract assertions, blocks, or translation units.
attribute-specifier-seq:attribute-specifier attribute-specifier-seqoptattribute-specifier:[[attribute-using-prefixopt attribute-list]]
[[annotation-list]]
alignment-specifieralignment-specifieralignas(type-id...opt)
alignas(constant-expression...opt)[. . .]
Change the entire subclause 9.13.2 [dcl.align] as follows:
alignment-specifieralignas(type-id...opt)
alignas(constant-expression...opt)1 An alignment-specifier may be applied to
a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, or an exception-declaration (14.4 [except.handle]). An alignment-specifier may also be applied to the declaration of a class (in an elaborated-type-specifier (9.2.9.5 [dcl.type.elab]) or class-head (11 [class]), respectively).a declaration of
- (1.1) a class-name (11.1 [class.pre], 9.2.9.5 [dcl.type.elab]) or
- (1.2) a variable, except for
An alignment-specifier with an ellipsis is a pack expansion (13.7.4 [temp.variadic]).
2 When the alignment-specifier is of the form
alignas( constant-expression ):, the constant-expression shall be an integral constant expression that satisfies the requirements of an alignment requirement (6.8.3 [basic.align]).
- (2.1)
the constant-expression shall be an integral constant expression- (2.2)
if the constant expression does not evaluate to an alignment value (6.8.3 [basic.align]), or evaluates to an extended alignment and the implementation does not support that alignment in the context of the declaration, the program is ill-formed.3 An alignment-specifier of the form
alignas( type-id )has the same effect asalignas(alignof( type-id )).4 The alignment requirement of an entity is the strictest nonzero alignment specified by its alignment-specifiers, if any; otherwise, the alignment-specifiers have no effect.
5 The combined effect of all alignment-specifiers in a declaration shall not specify an alignment that is less strict than the alignment that would be required for the entity being declared if all alignment-specifiers appertaining to that entity were omitted.
[Example:— end example ]struct alignas(8) S {}; struct alignas(1) U { S s; }; // error:Uspecifies an alignment that is less strict than if thealignas(1)were omitted.6
If the defining declaration of an entity has an alignment-specifier, any non-defining declaration of that entity shall either specify equivalent alignment or have no alignment-specifier. Conversely, if any declaration of an entity has an alignment-specifier, every defining declaration of that entity shall specify an equivalent alignment. No diagnostic is required if declarations of an entity have different alignment-specifiers in different translation units.If two declarations of an entity does not give it equivalent alignment requirement, the program is ill-formed; no diagnostic is required if neither declaration is reachable from the other.[Example:— end example ]// Translation unit #1: struct S {alignas(4)int x; } s, *p = &s; // Translation unit #2: struct alignas(164) S; // ill-formed, no diagnostic required: definition ofSlacksalignmentalignment-specifier extern S* p;[Example: An aligned buffer with an alignment requirement of
Aand holdingNelements of typeTcan be declared as:alignas(T) alignas(A) T buffer[N];Specifying
alignas(T)ensures that the final requested alignment will not be weaker thanalignof(T), and therefore the program will not be ill-formed. — end example ][Example:— end example ]alignas(double) void f(); // error: alignment applied to function alignas(double) unsigned char c[sizeof(double)]; // array of characters, suitably aligned for adoubleextern unsigned char c[sizeof(double)]; // noalignasnecessary alignas(float) extern unsigned char c[sizeof(double)]; // error: different alignment in declaration