Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions changelog/dmd.warn-unused-params.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
New preview flag ``-preview=warnunusedparams`` to warn on unused function parameters

A new ``-preview=warnunusedparams`` introduces warnings for named function parameters that are not referenced by the function body.

```d
void foo(int x, int y) // Warning: function parameter `y` is never used
{
return x * 2;
}
```

To suppress the warning, either omit the parameter name or use ``cast(void)``:

```d
void callback(int x, int) {} // unnamed parameter inhibits warning

void bar(int x, int y)
{
cast(void)y; // explicitly mark as unused, useful in conditional compilation
use(x);
}
```
3 changes: 3 additions & 0 deletions compiler/src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,9 @@ dmd -cov -unittest myprog.d
"https://dlang.org/spec/attribute.html#system-variables"),
Feature("fastdfa", "useFastDFA",
"Fast dataflow analysis engine, experimental"),
Feature("warnunusedparams", "warnUnused",
"enable warnings for unused function parameters",
"https://dlang.org/spec/function.html#unused-params"),
];
}

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ extern (C++) class VarDeclaration : Declaration
bool dllExport; /// __declspec(dllexport)
mixin VarDeclarationExtra;
bool systemInferred; /// @system was inferred from initializer
bool wasUsed; /// variable was referenced
}

import dmd.common.bitfields : generateBitFields;
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -7163,6 +7163,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

if (auto v = e.var.isVarDeclaration())
{
v.wasUsed = true;
if (v.checkNestedReference(sc, e.loc))
return setError();
}
Expand Down Expand Up @@ -7212,6 +7213,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

if (vd)
{
vd.wasUsed = true;
if (vd.checkNestedReference(sc, e.loc))
return setError();

Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -6639,6 +6639,8 @@ class VarDeclaration : public Declaration
bool inAlignSection(bool v);
bool systemInferred() const;
bool systemInferred(bool v);
bool wasUsed() const;
bool wasUsed(bool v);
private:
uint32_t bitFields;
public:
Expand Down Expand Up @@ -8198,6 +8200,7 @@ struct Param final
FeatureState dtorFields;
FeatureState systemVariables;
bool useFastDFA;
bool warnUnused;
CHECKENABLE useInvariants;
CHECKENABLE useIn;
CHECKENABLE useOut;
Expand Down Expand Up @@ -8282,6 +8285,7 @@ struct Param final
fixImmutableConv(),
fix16997(true),
useFastDFA(),
warnUnused(),
useInvariants((CHECKENABLE)0u),
useIn((CHECKENABLE)0u),
useOut((CHECKENABLE)0u),
Expand Down Expand Up @@ -8327,7 +8331,7 @@ struct Param final
timeTraceFile()
{
}
Param(bool obj, bool readStdin = false, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting useWarnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = true, bool rewriteNoExceptionToSeq = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), Edition edition = (Edition)2023u, void* editionFiles = nullptr, FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState safer = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, bool useFastDFA = false, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useNullCheck = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, CLIIdentifierTable dIdentifierTable = (CLIIdentifierTable)0u, CLIIdentifierTable cIdentifierTable = (CLIIdentifierTable)0u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<ImportPathInfo > imppath = Array<ImportPathInfo >(), Array<const char* > fileImppath = Array<const char* >(), _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), bool debugEnabled = false, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > cppswitches = Array<const char* >(), const char* cpp = nullptr, Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}, bool fullyQualifiedObjectFiles = false, bool timeTrace = false, uint32_t timeTraceGranularityUs = 500u, const char* timeTraceFile = nullptr) :
Param(bool obj, bool readStdin = false, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting useWarnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = true, bool rewriteNoExceptionToSeq = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), Edition edition = (Edition)2023u, void* editionFiles = nullptr, FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState safer = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, bool useFastDFA = false, bool warnUnused = false, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useNullCheck = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, CLIIdentifierTable dIdentifierTable = (CLIIdentifierTable)0u, CLIIdentifierTable cIdentifierTable = (CLIIdentifierTable)0u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<ImportPathInfo > imppath = Array<ImportPathInfo >(), Array<const char* > fileImppath = Array<const char* >(), _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), bool debugEnabled = false, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > cppswitches = Array<const char* >(), const char* cpp = nullptr, Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}, bool fullyQualifiedObjectFiles = false, bool timeTrace = false, uint32_t timeTraceGranularityUs = 500u, const char* timeTraceFile = nullptr) :
obj(obj),
readStdin(readStdin),
multiobj(multiobj),
Expand Down Expand Up @@ -8375,6 +8379,7 @@ struct Param final
dtorFields(dtorFields),
systemVariables(systemVariables),
useFastDFA(useFastDFA),
warnUnused(warnUnused),
useInvariants(useInvariants),
useIn(useIn),
useOut(useOut),
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ extern (C++) struct Param
// https://issues.dlang.org/show_bug.cgi?id=14246
FeatureState systemVariables; // limit access to variables marked @system from @safe code
bool useFastDFA; // Use fast data flow analysis engine
bool warnUnused; // warn about unused function parameters

CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks
CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ struct Param
// https://issues.dlang.org/show_bug.cgi?id=14246
FeatureState systemVariables; // limit access to variables marked @system from @safe code
d_bool useFastDFA; // Use fast data flow analysis engine
d_bool warnUnused; // warn about unused function parameters

CHECKENABLE useInvariants; // generate class invariant checks
CHECKENABLE useIn; // generate precondition checks
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/dmd/semantic3.d
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,16 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
}

// Warn about unused named parameters
if (global.params.warnUnused && funcdecl.parameters && funcdecl.fbody)
{
foreach (v; *funcdecl.parameters)
{
if (!v.wasUsed && !(v.storage_class & STC.temp))
.warning(v.loc, "function parameter `%s` is never used", v.ident.toChars());
}
}

/* If this function had instantiated with gagging, error reproduction will be
* done by TemplateInstance::semantic.
* Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
Expand Down
1 change: 1 addition & 0 deletions compiler/test/compilable/previewhelp.d
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ Upcoming language changes listed by -preview=name:
=fixImmutableConv disallow `void[]` data from holding immutable data (https://dlang.org/changelog/2.101.0.html#dmd.fix-immutable-conv, https://issues.dlang.org/show_bug.cgi?id=17148)
=systemVariables disable access to variables marked '@system' from @safe code (https://dlang.org/spec/attribute.html#system-variables)
=fastdfa Fast dataflow analysis engine, experimental
=warnunusedparams enable warnings for unused function parameters (https://dlang.org/spec/function.html#unused-params)
----
*/
30 changes: 30 additions & 0 deletions compiler/test/fail_compilation/unused_params.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// REQUIRED_ARGS: -w -preview=warnunusedparams -o-

/*
TEST_OUTPUT:
---
fail_compilation/unused_params.d(21): Warning: function parameter `x` is never used
fail_compilation/unused_params.d(21): Warning: function parameter `y` is never used
fail_compilation/unused_params.d(24): Warning: function parameter `x` is never used
Error: warnings are treated as errors
Use -wi if you wish to treat warnings only as informational.
---
*/

// No warning for used parameter
void used(int x) { auto z = x + 1; }

// No warning for cast(void)suppression
void suppressed(int x) { cast(void)x; }

// Warn for unused named parameters
void unused(int x, int y) {}

// No warning for unnamed parameter, warn for named
void partial(int x, int) {}

// No warning when no body
interface I
{
void iface(int x);
}
Loading