LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 8789 - Instantiating class template with friend declaration of C::f() hides in-line definition of C::f().
Summary: Instantiating class template with friend declaration of C::f() hides in-line ...
Status: RESOLVED FIXED
Alias: None
Product: clang
Classification: Unclassified
Component: C++ (show other bugs)
Version: trunk
Hardware: PC Linux
: P normal
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-14 08:04 PST by Hans Wennborg
Modified: 2010-12-15 02:28 PST (History)
4 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hans Wennborg 2010-12-14 08:04:47 PST
Compiling and linking the following code with Clang built from trunk r121764 fails:

template <typename T>
class ClassTemplate {
  friend void T::func();
};

class C {
 public:
  void func() {
    ClassTemplate<C> ct;
  }
};

int main() {
  C c;
  c.func();
}


$ clang++ /tmp/c.cc
/usr/bin/ld: /tmp/cc-QB69fY.o: in function main:/tmp/c.cc(.text+0x14): error: undefined reference to 'C::func()'
clang: error: linker command failed with exit code 1 (use -v to see invocation)


If C::func() is defined out-of-line, it works.

It seems like instantiating ClassTemplate<> with its friend declaration of T::func() somehow makes the in-line definition of C::func() disappear.
Comment 1 Nico Weber 2010-12-14 10:40:28 PST
If I add a "return 0" after the comment but before the call to Visit here

  // All of the Visit implementations for the various potential friend
  // declarations have to be carefully written to work for friend
  // objects, with the most important detail being that the target
  // decl should almost certainly not be placed in Owner.
  Decl *NewND = Visit(ND);

in TemplateDeclInstantiator::VisitFriendDecl(), the problem goes away. +rjmccall who added the comment – maybe it's obvious to him what needs to be done here.
Comment 2 Nico Weber 2010-12-14 15:25:16 PST
Further down the stack, removing this block

  if (isFriend) {
    if (Qualifier) {
      CXXScopeSpec SS;
      SS.setScopeRep(Qualifier);
      SS.setRange(D->getQualifierRange());
      DC = SemaRef.computeDeclContext(SS);

      if (DC && SemaRef.RequireCompleteDeclContext(SS, DC))
        return 0;
    } else {
      DC = SemaRef.FindInstantiatedContext(D->getLocation(),
                                           D->getDeclContext(),
                                           TemplateArgs);
    }
    if (!DC) return 0;
  }

from TemplateDeclInstantiator::VisitCXXMethodDecl() helps.
Comment 3 Nico Weber 2010-12-14 17:34:17 PST
Proposed patch (will add a test case):


Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp	(revision 121783)
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp	(working copy)
@@ -1437,7 +1436,7 @@
                             ? cast<NamedDecl>(FunctionTemplate)
                             : Method);
     if (isFriend)
-      Record->makeDeclVisibleInContext(DeclToAdd);
+      Owner->makeDeclVisibleInContext(DeclToAdd);
     else
       Owner->addDecl(DeclToAdd);
   }
Comment 4 Nico Weber 2010-12-14 17:36:57 PST
Probably better proposed patch:

@@ -1436,9 +1435,7 @@
     NamedDecl *DeclToAdd = (TemplateParams
                             ? cast<NamedDecl>(FunctionTemplate)
                             : Method);
-    if (isFriend)
-      Record->makeDeclVisibleInContext(DeclToAdd);
-    else
+    if (!isFriend)
       Owner->addDecl(DeclToAdd);
   }
Comment 5 Nico Weber 2010-12-14 18:44:45 PST
Patch attempt at http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-December/012590.html
Comment 6 John McCall 2010-12-14 22:01:16 PST
I fixed this in a totally different way in r121833.
Comment 7 Nico Weber 2010-12-15 02:28:35 PST
Our builders are happy again – thanks!