diff options
| author | Douglas Gregor <dgregor@apple.com> | 2010-05-17 17:34:56 +0000 | 
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2010-05-17 17:34:56 +0000 | 
| commit | 69f6a365d3b42c2d7e39de0d601acfad62173ad1 (patch) | |
| tree | b87b05832dc18cd729962c7273bb2992fc781083 | |
| parent | 176a9c4272ea29598cb96622f19fb3f38b895031 (diff) | |
| download | bcm5719-llvm-69f6a365d3b42c2d7e39de0d601acfad62173ad1.tar.gz bcm5719-llvm-69f6a365d3b42c2d7e39de0d601acfad62173ad1.zip  | |
Determine when the instantiation of a friend function defined inside a
class template conflicts with an existing (non-template)
definition. This is another part of PR6952.
llvm-svn: 103948
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 25 | ||||
| -rw-r--r-- | clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp | 31 | 
4 files changed, 55 insertions, 8 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 28332bdb9ab..535bd341794 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1219,9 +1219,8 @@ FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,  }  bool FunctionDecl::isImplicitlyInstantiable() const { -  // If this function already has a definition or is invalid, it can't be -  // implicitly instantiated. -  if (isInvalidDecl() || getBody()) +  // If the function is invalid, it can't be implicitly instantiated. +  if (isInvalidDecl())      return false;    switch (getTemplateSpecializationKind()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b573e2dcc94..5af5585f7f8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7527,7 +7527,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {    if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {      // Implicit instantiation of function templates and member functions of      // class templates. -    if (!Function->getBody() && Function->isImplicitlyInstantiable()) { +    if (Function->isImplicitlyInstantiable()) {        bool AlreadyInstantiated = false;        if (FunctionTemplateSpecializationInfo *SpecInfo                                  = Function->getTemplateSpecializationInfo()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 41c62186640..31284071ff6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1983,11 +1983,29 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,    if (Function->isInvalidDecl())      return; -  assert(!Function->getBody() && "Already instantiated!"); -    // Never instantiate an explicit specialization.    if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)      return; + +  const FunctionDecl *Definition = 0; +  if (Function->getBody(Definition)) { +    // We are trying to instantiate a friend function specialization inside +    // a class template, but there is already another (non-template) definition +    // of the same function. +    if (Definition->getTemplateSpecializationKind() == TSK_Undeclared) { +      InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); +      if (Inst) +        return;   +       +      Diag(Function->getLocation(), diag::err_redefinition)  +        << Function->getDeclName(); +      Diag(Definition->getLocation(), diag::note_previous_definition); +    } +     +    // We have an explicit instantiation (which already occurred) and an +    // implicit instantiation. Return without complaint. +    return; +  }    // Find the function body that we'll be substituting.    const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); @@ -2680,8 +2698,7 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {                                              Context.getSourceManager(),                                             "instantiating function definition"); -      if (!Function->getBody()) -        InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); +      InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);        continue;      } diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp index 6490aeb8ee0..a1d7c6933f0 100644 --- a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp @@ -7,3 +7,34 @@ struct X {  X<int> xi; // expected-note{{in instantiation of member function 'f' requested here}} +void f0(double) { } +void f0(int) { } // expected-note{{previous definition}} +void f1(int) { } // expected-note{{previous definition}} +void f2(int); +void f3(int); + +template<typename T> +struct X1 { +  friend void f0(T) { } // expected-error{{redefinition of}} +  friend void f1(T) { } // expected-error{{redefinition of}} +  friend void f2(T) { } // expected-error{{redefinition of}} +  friend void f3(T) { } // expected-error{{redefinition of}} +  friend void f4(T) { } // expected-error{{redefinition of}} +  friend void f5(T) { } // expected-error{{redefinition of}} + +  // FIXME: should have a redefinition error for f6(int) +  friend void f6(int) { } +}; + +void f2(int) { } // expected-note{{previous definition}} +void f4(int) { } // expected-note{{previous definition}} + +X1<int> x1a; // expected-note 6{{in instantiation of}} + +void f3(int) { } // expected-note{{previous definition}} +void f5(int) { } // expected-note{{previous definition}} + +X1<float> x1b; + + +X1<double> *X0d() { return 0;}  | 

