diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index 4395ff81ab0..76fe6ca490b 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -5928,67 +5928,6 @@ private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref O ++lines; } -/** - * Check signature of `pragma(printf)` function, print error if invalid. - * - * printf/scanf-like functions must be of the form: - * extern (C/C++) T printf([parameters...], const(char)* format, ...); - * or: - * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); - * - * Params: - * funcdecl = function to check - * f = function type - * sc = scope - */ -void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc) -{ - static bool isPointerToChar(Parameter p) - { - if (auto tptr = p.type.isTypePointer()) - { - return tptr.next.ty == Tchar; - } - return false; - } - - bool isVa_list(Parameter p) - { - return p.type.equals(target.va_listType(funcdecl.loc, sc)); - } - - const nparams = f.parameterList.length; - const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); - if (!(f.linkage == LINK.c || f.linkage == LINK.cpp)) - { - .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage," - ~" not `extern(%s)`", - p, funcdecl.toChars(), f.linkage.linkageToChars()); - } - if (f.parameterList.varargs == VarArg.variadic) - { - if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1]))) - { - .error(funcdecl.loc, "`pragma(%s)` function `%s` must have" - ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`", - p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); - } - } - else if (f.parameterList.varargs == VarArg.none) - { - if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) && - isVa_list(f.parameterList[nparams - 1]))) - .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~ - " signature `%s %s([parameters...], const(char)*, va_list)`", - p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars()); - } - else - { - .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter", - p, funcdecl.toChars()); - } -} - /********************************************* * Search for ident as member of d. * Params: diff --git a/compiler/src/dmd/funcsem.d b/compiler/src/dmd/funcsem.d index 3502916c057..ae14057807b 100644 --- a/compiler/src/dmd/funcsem.d +++ b/compiler/src/dmd/funcsem.d @@ -3339,3 +3339,64 @@ extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t, ref StringTable!Type return true; } } + +/** + * Check signature of `pragma(printf)` function, print error if invalid. + * + * printf/scanf-like functions must be of the form: + * extern (C/C++) T printf([parameters...], const(char)* format, ...); + * or: + * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); + * + * Params: + * funcdecl = function to check + * f = function type + * sc = scope + */ +private void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc) +{ + static bool isPointerToChar(Parameter p) + { + if (auto tptr = p.type.isTypePointer()) + { + return tptr.next.ty == Tchar; + } + return false; + } + + bool isVa_list(Parameter p) + { + return p.type.equals(target.va_listType(funcdecl.loc, sc)); + } + + const nparams = f.parameterList.length; + const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); + if (!(f.linkage == LINK.c || f.linkage == LINK.cpp)) + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage," + ~" not `extern(%s)`", + p, funcdecl.toChars(), f.linkage.linkageToChars()); + } + if (f.parameterList.varargs == VarArg.variadic) + { + if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1]))) + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have" + ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`", + p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); + } + } + else if (f.parameterList.varargs == VarArg.none) + { + if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) && + isVa_list(f.parameterList[nparams - 1]))) + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~ + " signature `%s %s([parameters...], const(char)*, va_list)`", + p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars()); + } + else + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter", + p, funcdecl.toChars()); + } +}