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



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to