Part of #23223 (M1 — standard-independent).
Summary
Parse C23 [[...]] attribute-specifier-sequences in ImportC. Modern C headers use them
pervasively, so without this, parsing aborts on real-world input. This is the largest
M1 item but needs no C-standard-selection mechanism: [[ is not valid C11 in these
positions, so accepting it is purely additive (and matches GCC/Clang, which
accept [[...]] as an extension before -std=c23).
Spec
N3220 6.7.13 Attributes — introduction 6.7.13.1, general/syntax 6.7.13.2.
Per-attribute subclauses: 6.7.13.3 nodiscard, 6.7.13.4 maybe_unused, 6.7.13.5
deprecated, 6.7.13.6 fallthrough, 6.7.13.7 noreturn/_Noreturn, 6.7.13.8
unsequenced/reproducible. See also the C attributes reference.
Grammar (N3220 6.7.13.2; opt = optional)
attribute-specifier-sequence:
attribute-specifier-sequence(opt) attribute-specifier
attribute-specifier:
[ [ attribute-list ] ]
attribute-list:
attribute(opt)
attribute-list , attribute(opt)
attribute:
attribute-token attribute-argument-clause(opt)
attribute-token:
standard-attribute
attribute-prefixed-token
standard-attribute:
identifier
attribute-prefixed-token:
attribute-prefix :: identifier
attribute-prefix:
identifier
attribute-argument-clause:
( balanced-token-sequence(opt) )
balanced-token-sequence:
balanced-token
balanced-token-sequence balanced-token
balanced-token:
( balanced-token-sequence(opt) )
[ balanced-token-sequence(opt) ]
{ balanced-token-sequence(opt) }
any token other than a parenthesis, a bracket, or a brace
Constraints (6.7.13.2/2) — a standard-attribute identifier shall be one of:
deprecated, fallthrough, maybe_unused, nodiscard, noreturn, _Noreturn,
unsequenced, reproducible.
Semantics (6.7.13.2/3) relevant to the parser:
- An
attribute-specifier containing no attributes ([[]]) has no effect; order within
an attribute-list is not significant.
- A standard attribute
attr and the form __attr__ behave identically (6.7.13.1/4) —
normalize surrounding __ before dispatch.
- A keyword used as an
attribute-token is treated as an identifier (so [[_Noreturn]]
is well-formed).
- The argument clause is a
balanced-token-sequence, not an expression — skip it by
paren/bracket/brace balancing (reuse cparseParens()), reading the actual contents
only for deprecated/nodiscard message strings.
Approach
Mirror the existing GNU parser. cparseGnuAttributes/cparseGnuAttribute (cparse.d:3618)
already feed the Specifier struct (cparse.d:4655) which applySpecifier/
specifiersToSTC (cparse.d:4683/4970) turn into D AST nodes — reuse that machinery
end to end (no new AST nodes).
Add:
cparseCAttributes(ref Specifier) — loop while the next two tokens are [ [
(the lexer emits two TOK.leftBracket; use peekNext() so a lone [ for array
subscripting is never misparsed), parse a comma-separated list (trailing comma
allowed), consume the closing ] ].
cparseCAttribute(ref Specifier) — one attribute-token [ ( balanced-tokens ) ].
Accept namespaced prefix :: name (gnu::, clang::, msvc::). Normalize standard
attributes spelled with surrounding __ (__deprecated__ -> deprecated).
New Id entries (id.d) for the attribute names that don't exist yet
(maybe_unused, nodiscard, fallthrough, unsequenced, reproducible, and the
gnu/clang/msvc prefixes); deprecated/noreturn already exist.
Attribute -> ImportC mapping
| Attribute |
N3220 § |
Handling |
deprecated / deprecated("msg") |
6.7.13.5 |
-> Specifier._deprecated / depMsg -> DeprecatedDeclaration |
noreturn / _Noreturn |
6.7.13.7 |
-> SCW.x_Noreturn |
nodiscard / nodiscard("msg") |
6.7.13.3 |
accept + ignore (no D equivalent; candidate future warning) |
maybe_unused |
6.7.13.4 |
accept + ignore |
fallthrough |
6.7.13.6 |
accept + ignore (statement attribute) |
unsequenced / reproducible |
6.7.13.8 |
accept + ignore |
namespaced (gnu::..., clang::...) / unknown |
6.7.13.1 |
scan + ignore (consume balanced ( ... )) |
Every code site and test carries a // C23 6.7.13.x clause comment.
Injection points
Accept [[...]] everywhere GNU __attribute__ is already consumed — mirror each
existing call site:
- declaration start (
cparseDeclarationSpecifiers, ~cparse.d:2516) and the
startsDeclarationSpecifiers/statement dispatch guards
- after
* in a declarator (~cparse.d:2927)
- init-declarator suffix (~
cparse.d:1892)
- function parameters (~
cparse.d:3268)
- struct/union tags & members (~
cparse.d:4037/4079/4241)
- enum tags & enumerators (~
cparse.d:3905/3953/3971/3989)
- statement-leading
[[fallthrough]]; / [[maybe_unused]] int x; (cparseStatement)
This satisfies the hard requirement that [[...]] parse anywhere __attribute__ does.
Out of scope / deferred (note here as they come up)
- Rarer attribute positions (e.g. mid specifier-qualifier-list in
sizeof(T [[...]]),
after the declarator-id inside array brackets) — defer; call them out in this issue.
- Mapping
nodiscard to an actual D diagnostic — future enhancement.
Acceptance criteria
Part of #23223 (M1 — standard-independent).
Summary
Parse C23
[[...]]attribute-specifier-sequences in ImportC. Modern C headers use thempervasively, so without this, parsing aborts on real-world input. This is the largest
M1 item but needs no C-standard-selection mechanism:
[[is not valid C11 in thesepositions, so accepting it is purely additive (and matches GCC/Clang, which
accept
[[...]]as an extension before-std=c23).Spec
N3220 6.7.13 Attributes — introduction 6.7.13.1, general/syntax 6.7.13.2.
Per-attribute subclauses: 6.7.13.3
nodiscard, 6.7.13.4maybe_unused, 6.7.13.5deprecated, 6.7.13.6fallthrough, 6.7.13.7noreturn/_Noreturn, 6.7.13.8unsequenced/reproducible. See also the C attributes reference.Grammar (N3220 6.7.13.2;
opt= optional)Constraints (6.7.13.2/2) — a
standard-attributeidentifier shall be one of:deprecated,fallthrough,maybe_unused,nodiscard,noreturn,_Noreturn,unsequenced,reproducible.Semantics (6.7.13.2/3) relevant to the parser:
attribute-specifiercontaining no attributes ([[]]) has no effect; order withinan
attribute-listis not significant.attrand the form__attr__behave identically (6.7.13.1/4) —normalize surrounding
__before dispatch.attribute-tokenis treated as an identifier (so[[_Noreturn]]is well-formed).
balanced-token-sequence, not an expression — skip it byparen/bracket/brace balancing (reuse
cparseParens()), reading the actual contentsonly for
deprecated/nodiscardmessage strings.Approach
Mirror the existing GNU parser.
cparseGnuAttributes/cparseGnuAttribute(cparse.d:3618)already feed the
Specifierstruct (cparse.d:4655) whichapplySpecifier/specifiersToSTC(cparse.d:4683/4970) turn into D AST nodes — reuse that machineryend to end (no new AST nodes).
Add:
cparseCAttributes(ref Specifier)— loop while the next two tokens are[[(the lexer emits two
TOK.leftBracket; usepeekNext()so a lone[for arraysubscripting is never misparsed), parse a comma-separated list (trailing comma
allowed), consume the closing
]].cparseCAttribute(ref Specifier)— oneattribute-token [ ( balanced-tokens ) ].Accept namespaced
prefix :: name(gnu::,clang::,msvc::). Normalize standardattributes spelled with surrounding
__(__deprecated__->deprecated).New
Identries (id.d) for the attribute names that don't exist yet(
maybe_unused,nodiscard,fallthrough,unsequenced,reproducible, and thegnu/clang/msvcprefixes);deprecated/noreturnalready exist.Attribute -> ImportC mapping
deprecated/deprecated("msg")Specifier._deprecated/depMsg->DeprecatedDeclarationnoreturn/_NoreturnSCW.x_Noreturnnodiscard/nodiscard("msg")maybe_unusedfallthroughunsequenced/reproduciblegnu::...,clang::...) / unknown( ... ))Every code site and test carries a
// C23 6.7.13.xclause comment.Injection points
Accept
[[...]]everywhere GNU__attribute__is already consumed — mirror eachexisting call site:
cparseDeclarationSpecifiers, ~cparse.d:2516) and thestartsDeclarationSpecifiers/statement dispatch guards*in a declarator (~cparse.d:2927)cparse.d:1892)cparse.d:3268)cparse.d:4037/4079/4241)cparse.d:3905/3953/3971/3989)[[fallthrough]];/[[maybe_unused]] int x;(cparseStatement)This satisfies the hard requirement that
[[...]]parse anywhere__attribute__does.Out of scope / deferred (note here as they come up)
sizeof(T [[...]]),after the declarator-id inside array brackets) — defer; call them out in this issue.
nodiscardto an actual D diagnostic — future enhancement.Acceptance criteria
compilabletest exercising each mapped/ignored attribute in each injectionpoint above, each with its
// C23 6.7.13.xcomment.fail_compilationtest (compiled with-de) confirming[[deprecated]]/[[deprecated("msg")]]fire the deprecation message.changelog/dmd.importc-c23-attributes.dd).__attribute__tests.