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
Should NamedDecl::declarationReplaces consider friend status? #30342
Comments
Hi Yaron! This would make sense to me. Let's wait for Richard's opinion. This is a busy week because of the C++ standards committee meeting. Cheers, Vassil |
I believe this fixes two FIXME in SemaTemplate/friend-template.cpp:
|
I don't think the proposed change is correct; we should use something like if (getFriendObjectKind() > OldD->getFriendObjectKind() && The > is needed so that a non-friend can properly replace a friend, and a visible friend can properly replace an invisible friend. The definition check is needed for cases like: void f(); ... where we want the 'noreturn' attribute to be visible in g(). Beyond that, I'm concerned that this may lead to us silently losing GNU attributes (or other properties that might be altered by the friend declaration) in cases like: void f(); ... because name lookup would only find the non-friend version of 'f'. That said, perhaps we should consider rejecting GNU attributes on non-defining friend declarations, in the same way that C++11 attributes are ill-formed on such declarations, as a prerequisite for this change. We'd need to do some investigation to see if there is any significant amount of real code relying on our current behaviour. |
This makes sense. isThisDeclarationADefinition is available for VarDecl, FunctionDecl, TagDecl, FunctionTemplateDecl, ClassTemplateDecl, VarTemplateDecl. For other Decls which has no meaning for definition and no isThisDeclarationADefinition, is this condition always false or decays to if (getFriendObjectKind() > OldD->getFriendObjectKind()) or maybe it makes no sense because they won't have friend kind and hence it will be always false? |
That seems correct. |
reduced case from Richard Smith! While building module 'x': r300443 was reverted in r300497. |
the replacement condition may need to consider modules? with the reproducer, it prevents this replacement: this= OldD= causing: |-FunctionTemplateDecl 0x23515b2ae58 prev 0x23515b2ab28 <line:3:1, col:37> col:32 in (local) x.b hidden f but FunctionDecl 0x23515b2adb8 should have been in (local) x.b same as the FunctionTemplateDecl 0x23515b2ae58. Richard, what do you think? |
Extended Description
Given the code
namespace boost {
template class shared_ptr {
template friend class shared_ptr;
};
}
shared_ptr c;
shared_ptr i;
shared_ptr is created with its TemplateDecl being the class shared_ptr while shared_ptr TemplateDecl is the friend TemplateDecl created in shared_ptr.
This happens because the friend TemplateDecl created in shared_ptr replaces the original class TemplateDecl.
It seems inconsistent that both ClassTemplateSpecializationDecl have different TemplateDecl.
To solve this, we could demand same friendness in NamedDecl::declarationReplaces
bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
...
// Friend should not replace non-friend.
if (OldD->getFriendObjectKind() != getFriendObjectKind())
return false;
The text was updated successfully, but these errors were encountered: