New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[class.access] Eliminate the friend case for protected member access from derived class #3672
base: main
Are you sure you want to change the base?
Conversation
Hmm. It's unclear whether [class.access]p1 is abstractly talking about a direct member of a class, or about a member of a class when named as a member of some (possibly) different class. We should clarify. I think it probably does mean the latter, which would make this change correct. Maybe adding a note:
would help? |
@@ -4472,8 +4472,8 @@ | |||
\indextext{access control!\idxcode{protected}}% | |||
protected; | |||
that is, its name can be used only by members and friends | |||
of the class in which it is declared, by classes derived from that class, and by their | |||
friends (see~\ref{class.protected}). | |||
of the class in which it is declared, and members of classes derived from that class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"... and by members of classes derived..." (add "by" to keep the sentence structure manageable)
@@ -4472,8 +4472,8 @@ | |||
\indextext{access control!\idxcode{protected}}% | |||
protected; | |||
that is, its name can be used only by members and friends | |||
of the class in which it is declared, by classes derived from that class, and by their | |||
friends (see~\ref{class.protected}). | |||
of the class in which it is declared, and members of classes derived from that class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more concern here: We change "by classes" to "by members of classes". This change seems to exclude the base-specifier, which is not in a member. Example:
struct B { };
struct D1 : protected B { };
struct D2 : D1 {};
I think the injected-class-name B is protected in D1, thus accessible from D2. But the name doesn't appear in a member.
That said, this paragraph is just one of those intro sentences where the actual rules appear later. (Note the funny punctuation, btw.) So, we shouldn't say wrong things, but we don't need to be ultra-precise either.
@zygoloid , I'm not in favor of adding a note here. This is an intro sentence, so let's keep it as vague as we possibly can. |
@zygoloid @jensmaurer Actually I opened this PR a bit too quickly. After thinking about member access rules more, I realized that the root of the problem in [class.access/1] is that the paragraph mixes direct access (correctly described in [class.access/base-5.1], [class.access/base-5.2], [class.access/base-5.3], [class.access/base-5.4] and [class.access/class.protected-1]) and inheritance access (correctly described in [class.access/base-1]). It should either talk about one or the other, not both at the same time. So I plan to open a better PR than this one (or update this one) in the following days since this PR did not solve the real problem. I published my thoughts in this Stack Overflow post: I am trying to fully understand member access rules defined in multiple paragraphs of the [class.access] section of the C++ standard. They are quite complex or even confusing therefore I need a short but accurate and exhaustive summary. I compiled this program to test the accessibility of protected members in several situations (since the rules for protected members are the most complex):1 #include <iostream>
class B {
protected:
int i = 1;
static int const I = 1;
};
class X: public B {
protected:
int j = 2;
static int const J = 2;
public:
void f();
friend void g();
};
class D: public X {
protected:
int k = 3;
static int const K = 3;
};
void X::f() {
B b;
X x;
D d;
//std::cout << b.i; // error: 'i' is a protected member of 'B'
std::cout << b.I;
std::cout << x.i;
std::cout << x.I;
std::cout << x.j;
std::cout << x.J;
std::cout << d.i;
std::cout << d.I;
std::cout << d.j;
std::cout << d.J;
//std::cout << d.k; // error: 'k' is a protected member of 'D'
//std::cout << d.K; // error: 'K' is a protected member of 'D'
}
void g() {
B b;
X x;
D d;
//std::cout << b.i; // error: 'i' is a protected member of 'B'
//std::cout << b.I; // error: 'I' is a protected member of 'B'
std::cout << x.i;
std::cout << x.I;
std::cout << x.j;
std::cout << x.J;
std::cout << d.i;
std::cout << d.I;
std::cout << d.j;
std::cout << d.J;
//std::cout << d.k; // error: 'k' is a protected member of 'D'
//std::cout << d.K; // error: 'K' is a protected member of 'D'
}
int main() {
B b;
X x;
D d;
//std::cout << b.i; // error: 'i' is a protected member of 'B'
//std::cout << b.I; // error: 'I' is a protected member of 'B'
//std::cout << x.i; // error: 'i' is a protected member of 'B'
//std::cout << x.I; // error: 'I' is a protected member of 'B'
//std::cout << x.j; // error: 'j' is a protected member of 'X'
//std::cout << x.J; // error: 'J' is a protected member of 'X'
//std::cout << d.i; // error: 'i' is a protected member of 'B'
//std::cout << d.I; // error: 'I' is a protected member of 'B'
//std::cout << d.j; // error: 'j' is a protected member of 'X'
//std::cout << d.J; // error: 'J' is a protected member of 'X'
//std::cout << d.k; // error: 'k' is a protected member of 'D'
//std::cout << d.K; // error: 'K' is a protected member of 'D'
return 0;
} I came to this conclusion on direct accessibility:2
Is my summary accurate and exhaustive? 1 I used the Clang 9.0.0 compiler with C++ 17. 2 Access to a member 3 My clause here differs slightly from the referenced clause of the standard [class.access/base-5.4]:
This is intended as the compiler behaves differently and my feeling is that the compiler is right. In my opinion there are two problems with the clause of the standard:
|
This is too far into the technical details to address without CWG oversight. |
Could you please rebase? |
This PR will fix an inconsistency in the specification described here:
https://stackoverflow.com/q/60178872/2326961