erik.pilkington updated this revision to Diff 168939.
erik.pilkington added a comment.

Merge the common pointers rather than trying to use the previous one. Thanks!


https://reviews.llvm.org/D53046

Files:
  clang/include/clang/AST/DeclTemplate.h
  clang/lib/AST/DeclTemplate.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/friend-template-redecl.cpp

Index: clang/test/SemaCXX/friend-template-redecl.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/friend-template-redecl.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++17 -verify -emit-llvm-only %s
+
+// expected-no-diagnostics
+
+template <class T> void bar(const T &t) { foo(t); }
+
+template <class>
+struct HasFriend {
+  template <class T>
+  friend void foo(const HasFriend<T> &m) noexcept(false);
+};
+
+template <class T>
+void foo(const HasFriend<T> &m) noexcept(false) {}
+
+void f() {
+  HasFriend<int> x;
+  foo(x);
+  bar(x);
+}
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -10022,11 +10022,17 @@
     if (FunctionTemplateDecl *OldTemplateDecl =
             dyn_cast<FunctionTemplateDecl>(OldDecl)) {
       auto *OldFD = OldTemplateDecl->getTemplatedDecl();
-      NewFD->setPreviousDeclaration(OldFD);
-      adjustDeclContextForDeclaratorDecl(NewFD, OldFD);
       FunctionTemplateDecl *NewTemplateDecl
         = NewFD->getDescribedFunctionTemplate();
       assert(NewTemplateDecl && "Template/non-template mismatch");
+
+      // The call to MergeFunctionDecl above may have created some state in
+      // NewTemplateDecl that needs to be merged with OldTemplateDecl before we
+      // can add it as a redeclaration.
+      NewTemplateDecl->mergePrevDecl(OldTemplateDecl);
+
+      NewFD->setPreviousDeclaration(OldFD);
+      adjustDeclContextForDeclaratorDecl(NewFD, OldFD);
       if (NewFD->isCXXClassMember()) {
         NewFD->setAccess(OldTemplateDecl->getAccess());
         NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
Index: clang/lib/AST/DeclTemplate.cpp
===================================================================
--- clang/lib/AST/DeclTemplate.cpp
+++ clang/lib/AST/DeclTemplate.cpp
@@ -300,6 +300,42 @@
   return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size());
 }
 
+void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
+  using Base = RedeclarableTemplateDecl;
+
+  // If we haven't created a common pointer yet, then it can just be created
+  // with the usual method.
+  if (!Base::Common)
+    return;
+
+  Common *ThisCommon = static_cast<Common *>(Base::Common);
+  Common *PrevCommon = nullptr;
+  SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
+  for (; Prev; Prev = Prev->getPreviousDecl()) {
+    if (Prev->Base::Common) {
+      PrevCommon = static_cast<Common *>(Prev->Base::Common);
+      break;
+    }
+    PreviousDecls.push_back(Prev);
+  }
+
+  // If the previous redecl chain hasn't created a common pointer yet, then just
+  // use this common pointer.
+  if (!PrevCommon) {
+    for (auto *D : PreviousDecls)
+      D->Base::Common = ThisCommon;
+    return;
+  }
+
+  // Ensure we don't leak any important state.
+  assert(ThisCommon->Specializations.size() == 0 &&
+         !ThisCommon->InstantiatedFromMember.getPointer() &&
+         !ThisCommon->InstantiatedFromMember.getInt() &&
+         "Can't merge incompatible declarations!");
+
+  Base::Common = PrevCommon;
+}
+
 //===----------------------------------------------------------------------===//
 // ClassTemplateDecl Implementation
 //===----------------------------------------------------------------------===//
Index: clang/include/clang/AST/DeclTemplate.h
===================================================================
--- clang/include/clang/AST/DeclTemplate.h
+++ clang/include/clang/AST/DeclTemplate.h
@@ -1093,6 +1093,9 @@
   /// template.
   ArrayRef<TemplateArgument> getInjectedTemplateArgs();
 
+  /// Merge our RedeclarableTemplateDecl::Common with \param Prev.
+  void mergePrevDecl(FunctionTemplateDecl *Prev);
+
   /// Create a function template node.
   static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
                                       SourceLocation L,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to