diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 27 | ||||
| -rw-r--r-- | clang/test/PCH/cxx-friends.cpp | 8 | ||||
| -rw-r--r-- | clang/test/PCH/cxx-friends.h | 12 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/friend-template.cpp | 35 | 
5 files changed, 69 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 007869c4374..113a8fc3e54 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3658,6 +3658,8 @@ def err_member_def_undefined_record : Error<    "out-of-line definition of %0 from class %1 without definition">;  def err_member_def_does_not_match : Error<    "out-of-line definition of %0 does not match any declaration in %1">; +def err_friend_decl_does_not_match : Error< +  "friend declaration of %0 does not match any declaration in %1">;  def err_member_def_does_not_match_suggest : Error<    "out-of-line definition of %0 does not match any declaration in %1; "    "did you mean %2?">; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f1581e0c349..d4b09753d30 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -969,20 +969,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,            PrevDecl = (*Previous.begin())->getUnderlyingDecl();        }      } - -    if (CurContext->isDependentContext() && PrevClassTemplate) { -      // If this is a dependent context, we don't want to link the friend -      // class template to the template in scope, because that would perform -      // checking of the template parameter lists that can't be performed -      // until the outer context is instantiated. -      PrevDecl = PrevClassTemplate = 0; -    }    } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))      PrevDecl = PrevClassTemplate = 0;    if (PrevClassTemplate) { -    // Ensure that the template parameter lists are compatible. -    if (!TemplateParameterListsAreEqual(TemplateParams, +    // Ensure that the template parameter lists are compatible. Skip this check +    // for a friend in a dependent context: the template parameter list itself +    // could be dependent. +    if (!(TUK == TUK_Friend && CurContext->isDependentContext()) && +        !TemplateParameterListsAreEqual(TemplateParams,                                     PrevClassTemplate->getTemplateParameters(),                                          /*Complain=*/true,                                          TPL_TemplateMatch)) @@ -1031,8 +1026,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,    // Check the template parameter list of this declaration, possibly    // merging in the template parameter list from the previous class -  // template declaration. -  if (CheckTemplateParameterList(TemplateParams, +  // template declaration. Skip this check for a friend in a dependent +  // context, because the template parameter list might be dependent. +  if (!(TUK == TUK_Friend && CurContext->isDependentContext()) && +      CheckTemplateParameterList(TemplateParams,              PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,                                   (SS.isSet() && SemanticContext &&                                    SemanticContext->isRecord() && @@ -1044,9 +1041,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,    if (SS.isSet()) {      // If the name of the template was qualified, we must be defining the      // template out-of-line. -    if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && -        !(TUK == TUK_Friend && CurContext->isDependentContext())) { -      Diag(NameLoc, diag::err_member_def_does_not_match) +    if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) { +      Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match +                                      : diag::err_member_def_does_not_match)          << Name << SemanticContext << SS.getRange();        Invalid = true;      } diff --git a/clang/test/PCH/cxx-friends.cpp b/clang/test/PCH/cxx-friends.cpp index a8d75586e43..bdba42bbcb5 100644 --- a/clang/test/PCH/cxx-friends.cpp +++ b/clang/test/PCH/cxx-friends.cpp @@ -11,3 +11,11 @@ class F {      a->x = 0;    }  }; + +template<typename T> class PR12585::future_base::setter { +public: +  int f() { +    return promise<T*>().k; +  } +}; +int k = PR12585::future_base::setter<int>().f(); diff --git a/clang/test/PCH/cxx-friends.h b/clang/test/PCH/cxx-friends.h index 2a33f15a532..05dcc960663 100644 --- a/clang/test/PCH/cxx-friends.h +++ b/clang/test/PCH/cxx-friends.h @@ -4,3 +4,15 @@ class A {    int x;    friend class F;  }; + +namespace PR12585 { +  struct future_base { +    template<typename> class setter; +  }; +  template<typename> class promise { +    // We used to inject this into future_base with no access specifier, +    // then crash during AST writing. +    template<typename> friend class future_base::setter; +    int k; +  }; +} diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp index 2b05527cf17..9acbfdcea29 100644 --- a/clang/test/SemaTemplate/friend-template.cpp +++ b/clang/test/SemaTemplate/friend-template.cpp @@ -267,3 +267,38 @@ namespace PR12557 {    Bar<int> b;  } + +namespace PR12585 { +  struct A { }; +  template<typename> struct B { +    template<typename> friend class A::does_not_exist; // \ +     // expected-error {{friend declaration of 'does_not_exist' does not match any declaration in 'PR12585::A'}} +  }; + +  struct C { +    template<typename> struct D; +  }; +  template<typename> class E { +    int n; +    template<typename> friend struct C::D; +  }; +  template<typename T> struct C::D { +    int f() { +      return E<int>().n; +    } +  }; +  int n = C::D<void*>().f(); + +  struct F { +    template<int> struct G; +  }; +  template<typename T> struct H { +    // FIXME: As with cases above, the note here is on an unhelpful declaration, +    // and should point to the declaration of G within F. +    template<T> friend struct F::G; // \ +      // expected-error {{different type 'char' in template redeclaration}} \ +      // expected-note {{previous}} +  }; +  H<int> h1; // ok +  H<char> h2; // expected-note {{instantiation}} +}  | 

