#include <stdio.h> class A { protected: static void foo() { printf("HI\n"); } }; class B : public A { friend class C; }; class C { public: void useFoo() { A::foo(); } }; int main(int argc, char **argv) { C c; c.useFoo(); }
g++ compiles, clang complains that A::foo is protected and can't be used in C::useFoo.I know friendship is not inherited, but this is actually the reverse of inheriting, so does anyone has any pointer as to where i should open the bug? clang or gcc?
This is a clang bug, see http://llvm.org/bugs/show_bug.cgi?id=6840
ReplyDeletegcc ;)
ReplyDeleteBecause you use the baseclass A to call the function foo(). In this case the compiler should complain that A::foo is protected, but it should compile with B::foo.
Both or none or as you want.
ReplyDeleteIt is a different appreciation of the C++ standard.
Source
"... so does anyone has any pointer as to where i should open the bug? clang or gcc?"
ReplyDeleteWhy not both and let compiler developers decide since they should know the specification a little better that "normal" developers :)
I must admit I agree with the clang developer.
ReplyDeleteIt seems like a bug in the c++ specification, if it states to be ok.
Never in a million years would I expect the code to compile, and the code İsmail Dönmez refer to in the bug report is different (if that doesn't build it should be fixed), but the example in this blog seems really wrong to me and gcc should be fixed
I would say that GCC is ok. Here is what c++03 says about it in 11.2.4:
ReplyDeleteA member m is accessible when named in class N if
- ...
— m as a member of N is protected, and the reference occurs in a member or friend of class N, or in a member or friend of a class P derived from N, where m as a member of P is private or protected, or
- ...
We set m := foo, N := A and P := B and the clause fits perfectly.
Clang is far away from reaching GCC maturity and completeness, so you can be nearly sure GCC is right. I wouldn't even bother to messing with clang, because it's more like a toy right now.
ReplyDeleteI also think gcc is right, and it's also making sense (opposed to what Anonymouse wrote above): "friend class C" says that the class C has access to everything class B has access to (plus everything C has access to anyway). A function in B can do "A::foo()", so a function in C should be able to do so as well.
ReplyDelete> "friend class C" says that the class C has access to everything class B has access to
ReplyDeleteThen let's modify the example:
#include
class A
{
protected:void bar() const
{
printf("Mo\n");
}
};
class B : public A
{
friend class C;
};
class C
{
public:
void useBar(A const& a) const
{
a.bar();
}
};
int main(int argc, char **argv)
{
C c;
B b;
c.useBar(b);
}
-> oops ;)
According to my understanding of name lookup, foo() is qualified with "A", so the lookup is done in "A". A foo() can be found, but it is not accessible, so the code should not compile.
To everyone, maybe that's what the standard says, but no, it doesn't make sense.
ReplyDeleteClass C isn't friend with A but B. I don't see why the compiler should look into the class B.
Yeah,
ReplyDeleteI encountered this problem while building QtWebkit, and even had made a patch for clang some years ago, but it was rejected because the developer beleived it is a "bug" in the specification. http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-June/009310.html
@SexyMimi
It makes sens if you consider that C is a "helper" class of B, so C should access everything that B can access.
In that very case, it can be worked around by calling C::foo().
@Olivier Goffart it seems as if some developers confuse access control with security features. I see no other explanation for such a rejection.
ReplyDeleteThis is an old & well known way to work around the private / protected access rights in C++: deriving the class and declare the derived class as 'friend' of the class / function from which you want to access the function.
ReplyDeleteI don't know if this is intentional or a breach in C++ model, all I can say is that it has always worked like that, both in G++ and MSVC (just to add another, unrelated compiler to the two discussed).
I can't say it does make sense, though. My feelings is that is kinda "bug" in C++ specification, but if clang behaves differently it will cause problems compiling existing code...
Well, if you look at the mailing list, you can clearly see of the conversation that at least one clang developer sees this as a mistake in the C++ standard, and that they currently have no plan on fixing it. To me, some things will need patches, since it's a quite common structure to work around protected (http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-June/009320.html)
ReplyDelete>> By that you mean you would accept the patch?
>No, sorry, not without some more support. It's a hard question — at what point does an apparent drafting mistake in the standard become obligatory? — but I am comfortable with my current answer here.
How a million years fly (I'm commenter #4)
ReplyDeleteAfter reading Olivier's comment and assumming B::foo could be a different implementation than A::foo, and so the only way to access the A impl would be with A::foo
Since C is a friend it should indeed be able to access what B accesses, and so while it seemed illogical at first sight I must now admit I think the spec and g++ is right.
I would say g++ is correct in this instance. C and B are friend's but that's where the relationship ends, C should not be able to call A's private. C could use it's friendship with B to call A, but your code tries to call A directly. I would say that this is a call by proxy example.
ReplyDeleteIMHO.
g++ is right. I tried also some Borland's and Microsoft compilers, and they don't complain.
ReplyDelete