Skip to content
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

Instantiating class template with friend declaration of C::f() hides in-line definition of C::f(). #9161

Closed
zmodem opened this issue Dec 14, 2010 · 7 comments
Labels
bugzilla Issues migrated from bugzilla c++

Comments

@zmodem
Copy link
Collaborator

zmodem commented Dec 14, 2010

Bugzilla Link 8789
Resolution FIXED
Resolved on Dec 15, 2010 02:28
Version trunk
OS Linux
CC @DougGregor,@nico,@rjmccall

Extended Description

Compiling and linking the following code with Clang built from trunk r121764 fails:

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

class C {
public:
void func() {
ClassTemplate 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.

@nico
Copy link
Contributor

nico commented Dec 14, 2010

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.

@nico
Copy link
Contributor

nico commented Dec 14, 2010

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.

@nico
Copy link
Contributor

nico commented Dec 15, 2010

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(FunctionTemplate)
: Method);
if (isFriend)

  •  Record->makeDeclVisibleInContext(DeclToAdd);
    
  •  Owner->makeDeclVisibleInContext(DeclToAdd);
    
    else
    Owner->addDecl(DeclToAdd);
    }

@nico
Copy link
Contributor

nico commented Dec 15, 2010

Probably better proposed patch:

@@ -1436,9 +1435,7 @@
NamedDecl *DeclToAdd = (TemplateParams
? cast(FunctionTemplate)
: Method);

  • if (isFriend)
  •  Record->makeDeclVisibleInContext(DeclToAdd);
    
  • else
  • if (!isFriend)
    Owner->addDecl(DeclToAdd);
    }

@nico
Copy link
Contributor

nico commented Dec 15, 2010

@rjmccall
Copy link
Contributor

I fixed this in a totally different way in r121833.

@nico
Copy link
Contributor

nico commented Dec 15, 2010

Our builders are happy again – thanks!

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 3, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla c++
Projects
None yet
Development

No branches or pull requests

3 participants