Clang 3.3 assertion failure for local extern declarations of variables with names matching function parameters

Clang 3.3, when compiled with assertions enabled, fails an assertion for the following test case. I believe this code is ill-formed, but at least some versions of gcc accept this test case (I tested 4.6.3 and 4.8.0). Clang 3.2 accepts this test case as well.

I filed a bug report for the assertion failure [1], but thought it would be good to clarify expected behavior on the mailing list.

$ cat t.cpp
struct S;
void f(S *s) {
     extern S *s;
     s;
}

$ clang --version
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix

$ clang -c t.cpp
clang: llvm-3.3/tools/clang/lib/AST/Decl.cpp:932: void clang::NamedDecl::verifyLinkage() const: Assertion `!D || D->CachedLinkage == CachedLinkage' failed.

[1]: http://llvm.org/bugs/show_bug.cgi?id=16804

Tom.

The code is ill-formed. We’re supposed to catch this due to [basic.scope.block]p2: “A parameter name shall not be redeclared in the outermost block of the function definition” but our check for that seems to be broken or missing.

The code is ill-formed. We're supposed to catch this due to
[basic.scope.block]p2: "A parameter name shall not be redeclared in the
outermost block of the function definition" but our check for that seems to
be broken or missing.

Broken - I believe I was the last one to muck with this in an effort
to have it catch the same case, but with function-try blocks. I may've
broken something while I was there, or perhaps this case was always
broken.

Simple case working:

$ cat scope.cpp
void func(int i) {
  int i;
}
blaikie@blaikie:~/dev/scratch$ clang++-tot scope.cpp
scope.cpp:2:7: error: redefinition of 'i'
  int i;
      ^
scope.cpp:1:15: note: previous definition is here
void func(int i) {
              ^
1 error generated.

I think that's Clang's implementation of that rule, at least - though
I could be wrong.

The code is ill-formed. We’re supposed to catch this due to
[basic.scope.block]p2: “A parameter name shall not be redeclared in the
outermost block of the function definition” but our check for that seems to
be broken or missing.

Broken - I believe I was the last one to muck with this in an effort
to have it catch the same case, but with function-try blocks. I may’ve
broken something while I was there, or perhaps this case was always
broken.

Simple case working:

$ cat scope.cpp
void func(int i) {
int i;
}
blaikie@blaikie:~/dev/scratch$ clang+±tot scope.cpp
scope.cpp:2:7: error: redefinition of ‘i’
int i;
^
scope.cpp:1:15: note: previous definition is here
void func(int i) {
^
1 error generated.

I think that’s Clang’s implementation of that rule, at least - though
I could be wrong.

Hmm, we’re only diagnosing here because both declarations are definitions (which is why adding ‘extern’ causes us to accept it). Trying to reuse the redefinition check to catch this is clever, but wrong.

We also miss this case:

void f(int n) try {} catch (int n) {}

… though we diagnose it if ‘n’ is instead redefined inside either pair of {}.

And we get this case wrong too:

int i;
void f(int i) {{
extern int i;
}}

… because we don’t notice that the innermost ‘i’ is a redeclaration of the outermost one (though that’s probably more part of PR7560 than this bug).