Repository navigation
CWG3109 [class.protected] Update to cover splices #784
Description
Full name of submitter: Dan Katz
Reference (section label): [class.protected]/1
Issue description
[class.protected] establishes the "additional rule" for access to non-static data members in the context of forming a pointer-to-member. Just as [class.access.base]/5.3 waives access rules for members designated through a splice-expression, this clause should do the same. As the rules currently stand, the following is well-formed when m is a private member of Base:
class Base {
private:
int m;
public:
static constexpr auto rm = ^^m;
};
class Derived { static constexpr auto mp = &[:Base::rm:]; };but [class.protected]/1 implies that the same is ill-formed when m is a protected member of Base, since there is no nested-name-specifier that denotes Derived or a class derived from Derived. Furthermore, the phrase "naming class" is used, whereas P2996 replaced this term with "designating class". Lastly, because a nested-name-specifier can be a splice-expression (e.g., &[:reflection_of_class:]::member), the verb "designates" should be preferred in lieu of "denotes".
Worth noting: This paragraph fails to account for access that occur in unevaluated contexts, but addressing this seems to tread too closely to CWG2902 for comfort, so I'm leaving that as-is for now (but added a comment on the relevant issue).
Suggested resolution
Apply the following changes to [class.protected]/1:
An additional access check beyond those described earlier in [class.access] is applied when a non-static data member or non-static member function is a protected member of its
namingdesignating class ([class.access.base]).98 As described earlier, access to a protected member is granted because the reference occurs in a friend or direct member of some classC. If the access is to form a pointer to member ([expr.unary.op]), that member shall either be designated with a splice-expression or with a qualified name whosethenested-name-specifiershall denotedesignatesCor a class derived fromC. All other accesses involve a (possibly implicit) object expression ([expr.ref]). In this case, the class of the object expression shall beCor a class derived fromC.
Optionally, we could try to drive-by fix the "unevaluated context issue" by modifying the last two sentences as follows:
All other potentially evaluated accesses involve a (possibly implicit) object expression ([expr.ref]). In this case, the class of the object expression shall be
Cor a class derived fromC.
But if the interaction to CWG2902 is too close, then we can ignore it for now.
Activity
[-][section.label] Update [class.protected] to cover splices[/-][+][class.protected] Update to cover splices[/+]t3nsor commentedon Oct 25, 2025
If the member is designated by a splice-expression, shouldn't we skip the additional check in [class.protected] entirely? That's effectively how it works with private members.
katzdm commentedon Oct 25, 2025
Yes, but we achieve that behavior by explicitly sanctioning the access in in [class.access.base]/5.3. I'm seeking to achieve the same here with:
What do you think? Does my suggested wording achieve that? Do you think there's a simpler way of expressing it?
t3nsor commentedon Oct 25, 2025
You put the wording "that member shall either be designated with a splice-expression" in the part that talks about forming a pointer-to-member. It seems that the exemption should also apply to direct accesses (i.e. using
.). We can say something like this:katzdm commentedon Oct 25, 2025
That direction works for me as well!
katzdm commentedon Oct 25, 2025
Revised suggestion:
jensmaurer commentedon Oct 26, 2025
What's the addition of "potentially evaluated" doing? I think we want the special "protected" rules to apply even for unevaluated stuff.
t3nsor commentedon Oct 26, 2025
I think the issue is that the current text fails to account for the fact that you can have something like
sizeof(Base::m). It doesn't fall under "if the access is to form a pointer to member" nor does it involve an object expression because the implicit transformation doesn't happen in this case.jensmaurer commentedon Nov 2, 2025
... and we don't, in fact, apply the extra check for unevaluated stuff; is that the gist?
jensmaurer commentedon Nov 2, 2025
CWG3109
[-][class.protected] Update to cover splices[/-][+]CWG3109 [class.protected] Update to cover splices[/+]t3nsor commentedon Nov 2, 2025
Yes. It seems that the way implementations behave is that for unevaluated cases, the additional check applies only if you have a class member access (taking into account the fact that one is not formed implicitly).
So we should say something like this: "Otherwise, if the access involves a (possibly implicit) object expression, [...]. [Note: Some unevaluated accesses do not fall under any of the rules in this paragraph and therefore, no additional check applies to them.]"