Skip to content

ImportC C23: variadic functions with no named parameter (f(...) / f(int, ...)) #23232

Description

@PetarKirov

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

  • compilable test(s) exercising f(...) and f(int, ...), each declaration carrying its // C23 6.7.7.4 comment
  • fail_compilation test 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 a fail_compilation case, otherwise document that no error path remains
  • Changelog entry (changelog/dmd.importc-c23-variadic.dd)
  • No regression for existing tests (notably f(void) and f()/K&R behavior)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions