[cfe-dev] Weird issues (bug(s)?) with friend name injection and extern C and ambiguity
Evan Driscoll via cfe-dev
cfe-dev at lists.llvm.org
Sat May 21 23:48:43 PDT 2016
I apologize if this is the wrong venue for this, and apologize for the
wall of text. :-) I thought about filing a bug, except I realized I
don't really know what to report; there are two different things I am
not actually familiar enough with to understand whether or not this
code is actually legal or how it's legal. GCC, Clang++, and MSVC have
three different interpretations of this and a slight modification of
it. I was originally going to report this issue as just a "Clang's
error message was extremely unhelpful", but I'm not convinced there
isn't more going on than just that.
Without further ado, here's the code:
namespace namespace_with_injected_name {
class Boo {
friend struct ExternCStruct;
};
}
using namespace namespace_with_injected_name;
extern "C" {
struct ExternCStruct;
struct ExternCStruct; // yes, a second one (!)
}
ExternCStruct * p;
GCC accepts this code without question, at least on 4.8 and 4.9
MSVC claims the final declaration of p is an error because
"ExternCStruct" is ambiguous and gives a good explanation as to why:
1>... error C2872: 'ExternCStruct' : ambiguous symbol
1> could be '...(10) : ExternCStruct'
1> or '...(3) : namespace_with_injected_name::ExternCStruct'
Clang also fails, thinking it's ambiguous, but its error is not helpful:
14 : error: reference to 'ExternCStruct' is ambiguous
ExternCStruct * p;
11 : note: candidate found by name lookup is 'ExternCStruct'
struct ExternCStruct;
10 : note: candidate found by name lookup is 'ExternCStruct'
struct ExternCStruct;
so it "helpfully" pointed out I have two declarations in global scope,
but it does *not* indicate anything about Boo's friend, which seems
like the root cause of the error. I didn't even *know* that was the
problem until I minimized it to send it to you folks to report the
unhelpful error; unless I lost something during the translation,
apparently a coworker fixed it by accident, because we thought it was
a different issue.
(The above error output is based on https://gcc.godbolt.org/ and
claims to be 3.8; I was using an older version that didn't produce the
two notes.)
But it gets weirder.
Not only does Clang report the two extern C declarations in the
warning, but it actually *needs* both of them to give an error at all:
if you remove one, it compiles! At least according to the online
implementation.
Furthermore, I just noticed that the version above actually *does* on
my older Clang 3.6. Here's a slightly more complex version that
complies with neither version:
namespace namespace_with_injected_name {
class Boo {
friend struct ExternCStruct;
};
}
using namespace namespace_with_injected_name;
extern "C" {
struct ExternCStruct;
}
void f(ExternCStruct * state);
extern "C" {
struct ExternCStruct;
void g(ExternCStruct *ps) {
::f(ps);
}
(The :: actually improves the error quality a hair I think, but isn't
necessary to seeing what is happening.) This one is actually truer to
the error we were hitting.
Anyway, I'd be happy to file a bug if that's what would be preferred
and it looks like one to you all, provided that someone can inform me
as to what that bug might be so I don't have to call it "weird funky
thing with friend name injection or maybe extern C structs or
something". ;-)
Evan
More information about the cfe-dev
mailing list