diff --git a/changelog/dmd.foreach-shadow-error.dd b/changelog/dmd.foreach-shadow-error.dd new file mode 100644 index 000000000000..236c71e641be --- /dev/null +++ b/changelog/dmd.foreach-shadow-error.dd @@ -0,0 +1,32 @@ +Foreach variable shadowing is now an error + +A deprecation introduced in DMD 2.089.0 for foreach variables shadowing +outer scope symbols has been upgraded to an error. + +This affects both variables declared inside a foreach body that shadow +outer variables, and duplicate variable names in foreach parameter lists +when using `opApply`. + +--- +void main() +{ + int[int] arr; + int x; + foreach (i, j; arr) + { + int x; // Error: variable `x` is shadowing variable `...x` + } +} +--- + +--- +struct Foo +{ + int opApply(scope int delegate(size_t, size_t, ref uint)) => 0; +} + +void main() +{ + foreach (x, y, x; Foo()) {} // Error: variable `x` is shadowing variable `...x` +} +--- diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index bab85f4a96f3..0371f607ad9c 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -8731,17 +8731,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto decl = s2.isDeclaration(); if (decl && (decl.storage_class & STC.local)) continue; - if (sc.func.fes) - { - deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); - deprecationSupplemental(s2.loc, "declared here"); - } - else - { - error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); - errorSupplemental(s2.loc, "declared here"); + error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + errorSupplemental(s2.loc, "declared here"); + if (!sc.func.fes) return setError(); - } } } } diff --git a/compiler/test/fail_compilation/fail2195.d b/compiler/test/fail_compilation/fail2195.d index 6f6cd53b0e39..06bb09b05ebb 100644 --- a/compiler/test/fail_compilation/fail2195.d +++ b/compiler/test/fail_compilation/fail2195.d @@ -1,10 +1,9 @@ // https://issues.dlang.org/show_bug.cgi?id=2195 -// REQUIRED_ARGS: -de /* TEST_OUTPUT: --- -fail_compilation/fail2195.d(17): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable` -fail_compilation/fail2195.d(14): declared here +fail_compilation/fail2195.d(16): Error: variable `variable` is shadowing variable `fail2195.main.variable` +fail_compilation/fail2195.d(13): declared here --- */ diff --git a/compiler/test/fail_compilation/fail22584.d b/compiler/test/fail_compilation/fail22584.d new file mode 100644 index 000000000000..b194eccf1bc4 --- /dev/null +++ b/compiler/test/fail_compilation/fail22584.d @@ -0,0 +1,15 @@ +// https://github.com/dlang/dmd/issues/22584 +/* +TEST_OUTPUT: +--- +fail_compilation/fail22584.d(14): Error: variable `x` is shadowing variable `fail22584.main.__foreachbody_L14_C5.x` +fail_compilation/fail22584.d(14): declared here +--- +*/ + +struct Foo { + int opApply(scope int delegate(size_t, size_t, ref uint)) => 0; +} +void main() { + foreach (x, y, x; Foo()) {} +}