[PATCH] D21508: Make friend function template definition available if class is instantiated.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 24 17:01:08 PDT 2016
rsmith added a comment.
The model that the C++ standard seems to have settled on is that a friend function declaration that's instantiated from a definition is considered to be a definition, even if we've not instantiated its body yet. I think we should try to directly implement that rule.
================
Comment at: lib/AST/DeclTemplate.cpp:292-311
+FunctionTemplateDecl *FunctionTemplateDecl::getDefinition() const {
+ for (auto *R : redecls()) {
+ FunctionTemplateDecl *F = cast<FunctionTemplateDecl>(R);
+ if (F->isThisDeclarationADefinition())
+ return F;
+
+ // If template does not have a body, probably it is instantiated from
----------------
It seems to me that we're getting something fundamentally wrong in the way we model friend function definitions where we've instantiated the declaration but not the definition. Here's a case we get wrong on the non-function-template side:
template<typename T> struct X { friend void f() {} };
X<int> xi;
void f() {}
Line 3 should be ill-formed here due to redefinition, but we don't detect that because we don't believe that the declaration we instantiated on line 2 is a definition. That seems to be the heart of the problem.
Instead of adding this function, can you try changing `FunctionDecl::isThisDeclarationADefinition` to contain the above logic (that is: if this function is a friend that was instantiated from a definition, then it's a definition even if we don't have a body yet)?
================
Comment at: lib/Sema/SemaDecl.cpp:8856
+ (NewTemplateDecl->getFriendObjectKind() != Decl::FOK_None ||
+ OldTemplateDecl->getFriendObjectKind() != Decl::FOK_None))
+ if (FunctionTemplateDecl *NewDef = NewTemplateDecl->getDefinition())
----------------
This doesn't look right; the `OldTemplateDecl` might be `FOK_None` but could still have a definition as a `friend`.
I'm not convinced this is the right place for this check. There are two different cases here:
1) The redefinition error is introduced by parsing a definition in the source code. That should already be handled by `ActOnStartOfFunctionDef`.
2) The redefinition error is introduced by instantiating a friend function template declaration (that has a definition).
I think check (2) belongs in the template instantiation code rather than here. In fact, at the end of `TemplateDeclInstantiator::VisitFunctionDecl`, there is an attempt to enforce the relevant rule; it just doesn't get all the cases right.
================
Comment at: lib/Sema/SemaDecl.cpp:8857-8863
+ if (FunctionTemplateDecl *NewDef = NewTemplateDecl->getDefinition())
+ if (FunctionTemplateDecl *OldDef = OldTemplateDecl->getDefinition()) {
+ Diag(NewDef->getLocation(), diag::err_redefinition)
+ << NewDef->getDeclName();
+ Diag(OldDef->getLocation(), diag::note_previous_definition);
+ Redeclaration = false;
+ }
----------------
You should use `CheckForFunctionRedefinition` to catch this.
https://reviews.llvm.org/D21508
More information about the cfe-commits
mailing list