Part of #23223 (M1 — standard-independent).
Summary
C23 permits a function declarator whose parameter-type-list is a bare ellipsis (f(...)), i.e. a variadic function with no preceding named parameter. In C11 this was a constraint violation, so accepting it is purely additive: every valid C11 program keeps its meaning, and no CLI/standard-selection flag is required. ImportC already parses an unnamed typed parameter before the ellipsis (f(int, ...)); this change additionally drops the guard that rejected f(...). Standard-independent, enabled unconditionally in ImportC mode.
Spec
N3220 6.7.7.4 Function declarators (with grammar from 6.7.7.1 General — parameter-type-list / parameter-list); the standalone ... alternative of parameter-type-list is what allows the ellipsis with no preceding named parameter.
Grammar (N3220 6.7.7.1; opt = optional)
function-declarator:
direct-declarator ( parameter-type-list(opt) )
parameter-type-list:
parameter-list
parameter-list , ...
...
parameter-list:
parameter-declaration
parameter-list , parameter-declaration
parameter-declaration:
attribute-specifier-sequence(opt) declaration-specifiers declarator
attribute-specifier-sequence(opt) declaration-specifiers abstract-declarator(opt)
Semantics relevant to the parser (N3220 6.7.7.4):
- ¶8: "If the list terminates with an ellipsis (...), no information about the number or types of the parameters after the comma is supplied." Note the third
parameter-type-list alternative (... alone) has no preceding parameter-list, so the ellipsis may legitimately appear with zero named/typed parameters.
- ¶9: "The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters." (i.e.
f(void) stays distinct — out of scope here.)
Approach
Reuse the existing varargs machinery in cparseParameterList (compiler/src/dmd/cparse.d:3196). The function already maps a trailing ... to AST.VarArg.variadic and sets importBuiltins = true for __va_list_tag (compiler/src/dmd/cparse.d:3238-3239). The only obstacle is the C11-era guard at compiler/src/dmd/cparse.d:3236-3237:
if (parameters.length == 0) // func(...)
error("named parameter required before `...`");
Drop that if/error (the guard, not the surrounding ellipsis-handling block), so that when ... is the first and only thing in the list, parsing continues into the existing path that sets varargs = AST.VarArg.variadic, consumes the token, and check(TOK.rightParenthesis). The ImportC->D mapping is unchanged: f(...) becomes a D extern(C) function with VarArg.variadic, identical to how f(int, ...) is already handled. f(int, ...) (unnamed typed parameter before the ellipsis) already works and needs no change.
This mirrors the direction of dlang/dmd #23177 and #21157, which track ImportC variadic / parameter-list handling.
Change sites
compiler/src/dmd/cparse.d:3236-3237 — remove the if (parameters.length == 0) error("named parameter required before \...`");guard inside theTOK.dotDotDotbranch ofcparseParameterList, keeping importBuiltins = true;andvarargs = AST.VarArg.variadic; (compiler/src/dmd/cparse.d:3238-3239`).
Out of scope / deferred
Acceptance criteria
Part of #23223 (M1 — standard-independent).
Summary
C23 permits a function declarator whose parameter-type-list is a bare ellipsis (
f(...)), i.e. a variadic function with no preceding named parameter. In C11 this was a constraint violation, so accepting it is purely additive: every valid C11 program keeps its meaning, and no CLI/standard-selection flag is required. ImportC already parses an unnamed typed parameter before the ellipsis (f(int, ...)); this change additionally drops the guard that rejectedf(...). Standard-independent, enabled unconditionally in ImportC mode.Spec
N3220 6.7.7.4 Function declarators (with grammar from 6.7.7.1 General —
parameter-type-list/parameter-list); the standalone...alternative ofparameter-type-listis what allows the ellipsis with no preceding named parameter.Grammar (N3220 6.7.7.1;
opt= optional)Semantics relevant to the parser (N3220 6.7.7.4):
parameter-type-listalternative (...alone) has no precedingparameter-list, so the ellipsis may legitimately appear with zero named/typed parameters.f(void)stays distinct — out of scope here.)Approach
Reuse the existing varargs machinery in
cparseParameterList(compiler/src/dmd/cparse.d:3196). The function already maps a trailing...toAST.VarArg.variadicand setsimportBuiltins = truefor__va_list_tag(compiler/src/dmd/cparse.d:3238-3239). The only obstacle is the C11-era guard atcompiler/src/dmd/cparse.d:3236-3237:Drop that
if/error(the guard, not the surrounding ellipsis-handling block), so that when...is the first and only thing in the list, parsing continues into the existing path that setsvarargs = AST.VarArg.variadic, consumes the token, andcheck(TOK.rightParenthesis). The ImportC->D mapping is unchanged:f(...)becomes a Dextern(C)function withVarArg.variadic, identical to howf(int, ...)is already handled.f(int, ...)(unnamed typed parameter before the ellipsis) already works and needs no change.This mirrors the direction of dlang/dmd #23177 and #21157, which track ImportC variadic / parameter-list handling.
Change sites
compiler/src/dmd/cparse.d:3236-3237— remove theif (parameters.length == 0) error("named parameter required before \...`");guard inside theTOK.dotDotDotbranch ofcparseParameterList, keepingimportBuiltins = true;andvarargs = AST.VarArg.variadic;(compiler/src/dmd/cparse.d:3238-3239`).Out of scope / deferred
f()meaningf(void): ImportC deliberately keeps the permissiveVarArg.KRvariadicbehavior for empty parentheses (compiler/src/dmd/cparse.d:3214); C23's "empty parens ==(void)prototype" semantics are not changed here.f(void)handling is untouched (compiler/src/dmd/cparse.d:3204-3209).Acceptance criteria
compilabletest(s) exercisingf(...)andf(int, ...), each declaration carrying its// C23 6.7.7.4commentfail_compilationtest for the error path: not applicable —f(...)becomes valid and the only removed diagnostic is the dropped guard; if a residual misuse still errors, add afail_compilationcase, otherwise document that no error path remainschangelog/dmd.importc-c23-variadic.dd)f(void)andf()/K&R behavior)