Hi Martin, > Date: 2026-09-15 11:45:31+0200 > From: Martin Uecker > [...] > > Let's quote the text of the constraint, and I'll numerate the lines: > > > > 6.7.7.4 Function declarators > > @@ p4+1 > > 1 +Within a parameter declaration list, > > 2 +if an identifier used in a parameter’s array bound expression > > 3 +refers to a name declared later in the same list, > > 4 +no declaration of an identifier with the same name > > 5 +shall be visible from an enclosing scope. > > > > Let's write a translation unit: > > > > // foo.c > > > > int n; // global 'n' > > > > void f(int n); // fine, doesn't trigger line 2; it shadows > > > > void g(int n, int a[n]); // fine, doesn't trigger line 3; it shadows > > > > void h(int a[n]); // fine, doesn't trigger line 3; uses global 'n' > > > > void i(int a[n], int n); // Constraint violation > > > > void j(int n; int a[n], int n); // Constraint violation, but see below > > > > Does it make sense now? > > I already understand that. I do not want > > int n; > void i(int a[n], int n); > > to be a constraint violation, because if I write > > void i(int a[n], int n); > > and any header that later puts an "n" into file scope somewhere, even > in a library maintained by somebody else, perhaps a decade after the > original code was written, this then may cause a surprising > compilation errors. It is an action at a distance issue nobody > needs. > > > And the only reason why this may seem unlikely in this toy example > is that nobody would use a single letter "n" as a global variable, but > in real code not all parameters have such short names. > > > > > I would relax the constraint for case j(), since it's clearly okay. > > Since forward declarations are non-standard, we can't have the standard > > wording say something about forward declarations, but as QoI, I'd not > > trigger the diagnostic for j(). > > [...] > > My arguments is that currently, the following code has a meaning: > > > > int n; > > > > void i(int a[n], int n); > > > > If we add retroactive scoping, the semantics of that code would change. > > (Add 'static' if you care about ISO C not respecting [n].) > > Thus, functions using retroactive scoping need to prohibit this code, > > to avoid silent changes. > > On a theoretical level I can understand your argument. But in > reality this is a purely theoretical issue as nobody writes such  > code. Even using a global variable as length is already extremely > rare, but then using the same name as parameter while intending > to use the original global variable would seem to make such code > so unlikely that I do not think it exists. > > What is more common is to use a constant, e.g. a macro or > enumeration value. > > void i(int a[MAX_DIMS], int n); > > But then again, it seems very unlikely that writes > > enum { MAX_DIMS = 100 }; > > void i(int a[MAX_DIMS], int MAX_DIMS); > > with the intention that the first MAX_DIMS actually > refers to the global variable and not to the parameter. > If such code exits, it is  almost certainly already an > unintentional error. And you would not diagnose such an unintentional error? I think this seems to trigger again the discussion about whether we want constraints for things that should be diagnostics, but where the user should be allowed to continue translation. I guess I can live without the constraint, because QoI will result in compilers diagnosing this anyway. I expect GCC would add a new value -Wshadow=retroactive-parameter or something like that to warn specifically about this situation. > > As long as the constraint affects only functions using retroactive > > scoping and functions that we agree are currently bad (because they look > > like retroactive scoping, but they aren't), the constraint seems > > positive. > > It would be positive (although largely irrelevant), if not for  > the action-at-a-distance issue above (which I do not think is > irrelevant). > > > > I am not sure about this, I have seen WG14 add new functions with > > > the size later because people insisted it is more ideomatic (despite > > > the charter saying this should not be done). > > > > And I still do it for new str*() and mem*() functions, because, indeed, > > it is more idiomatic/consistent with related APIs. > > > > But that's a conscious decision. If you add such a function, then you > > either use GNU C's forward declarations to avoid the constraint, or you > > use a parameter name that you know won't be used elsewhere. > > Forward declaration are not standardized, so people avoid them. > > But the issue of name collision in local contexts is much more > serious. This is exactly the reason people come up with sophisticated > macro contraptions to create unique names for temporaries in > macros, and why people ask for lambdas to have clean alternative > instead that does not have such fundamental problems. Introducing > lambdas, but then breaking this in a way that it has the same issue > would be really a terrible idea. > > But, yes, this was my point: If we added that constraint,  > something like forward declarations could be used to avoid writing > fragile macros. > > > > > libc has it easy: a name reserved in the global namespace (__n) would > > work. It only needs to be self consistent, and not declare __n > > globally. Other libraries will have to prefix the parameters with the > > library prefix, I guess. > > I do not think that breaking fundamental language features such as scoping, > and requiring everybody to prefix all their names to prevent collisions > is a viable. Also a single prefix is not enough in nested macros, you > would need a unique identifier in each nested instance. > [...] > > Simple not having the constraint would also be ok with me. Agreed. Cheers, Alex > > Martin > --