elsteveogrande updated this revision to Diff 157682.
elsteveogrande added a comment.
Herald added a subscriber: chrib.

Rebase very old diff


Repository:
  rC Clang

https://reviews.llvm.org/D38320

Files:
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/PCH/cxx-templates.cpp
  test/PCH/cxx-templates.h

Index: test/PCH/cxx-templates.h
===================================================================
--- test/PCH/cxx-templates.h
+++ test/PCH/cxx-templates.h
@@ -361,3 +361,38 @@
 namespace MemberSpecializationLocation {
   template<typename T> struct A { static int n; };
 }
+
+// https://bugs.llvm.org/show_bug.cgi?id=34728
+namespace PR34728 {
+
+// case 1: defaulted `NonTypeTemplateParmDecl`, non-defaulted 2nd tpl param
+template <int foo = 10, class T>
+int func1(T const &);
+
+template <int foo, class T>
+int func1(T const &) {
+  return foo;
+}
+
+// case 2: defaulted `TemplateTypeParmDecl`, non-defaulted 2nd tpl param
+template <class A = int, class B>
+A func2(B const &);
+
+template <class A, class B>
+A func2(B const &) {
+  return A(20.0f);
+}
+
+// case 3: defaulted `TemplateTemplateParmDecl`, non-defaulted 2nd tpl param
+template <class T>
+struct Container { T const &item; };
+
+template <template <class> class C = Container, class D>
+C<D> func3(D const &);
+
+template <template <class> class C, class D>
+C<D> func3(D const &d) {
+  return Container<D>{d};
+}
+
+} // end namespace PR34728
Index: test/PCH/cxx-templates.cpp
===================================================================
--- test/PCH/cxx-templates.cpp
+++ test/PCH/cxx-templates.cpp
@@ -116,3 +116,19 @@
 #endif
   int k = A<int>::n;
 }
+
+// https://bugs.llvm.org/show_bug.cgi?id=34728
+namespace PR34728 {
+int test() {
+  // Verify with several TemplateParmDecl kinds, using PCH (incl. modules).
+  int z1 = func1(/*ignored*/2.718);
+  int z2 = func2(/*ignored*/3.142);
+  int tmp3 = 30;
+  Container<int> c = func3(tmp3);
+  int z3 = c.item;
+
+  // Return value is meaningless.  Just "use" all these values to avoid
+  // warning about unused vars / values.
+  return z1 + z2 + z3;
+}
+} // end namespace PR34728
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -1558,11 +1558,24 @@
 
   Record.push_back(D->wasDeclaredWithTypename());
 
-  bool OwnsDefaultArg = D->hasDefaultArgument() &&
-                        !D->defaultArgumentWasInherited();
-  Record.push_back(OwnsDefaultArg);
-  if (OwnsDefaultArg)
-    Record.AddTypeSourceInfo(D->getDefaultArgumentInfo());
+  TypeSourceInfo *OwnedDefaultArg = nullptr;
+  Decl const *InheritsFromDecl = nullptr;
+  if (D->hasDefaultArgument()) {
+    if (D->defaultArgumentWasInherited()) {
+      InheritsFromDecl = D->getDefaultArgStorage().getInheritedFrom();
+    } else {
+      OwnedDefaultArg = D->getDefaultArgumentInfo();
+    }
+  }
+
+  Record.push_back(OwnedDefaultArg != nullptr);
+  if (OwnedDefaultArg) {
+    Record.AddTypeSourceInfo(OwnedDefaultArg);
+  }
+  Record.push_back(InheritsFromDecl != nullptr);
+  if (InheritsFromDecl) {
+    Record.AddDeclRef(InheritsFromDecl);
+  }
 
   Code = serialization::DECL_TEMPLATE_TYPE_PARM;
 }
@@ -1589,11 +1602,26 @@
   } else {
     // Rest of NonTypeTemplateParmDecl.
     Record.push_back(D->isParameterPack());
-    bool OwnsDefaultArg = D->hasDefaultArgument() &&
-                          !D->defaultArgumentWasInherited();
-    Record.push_back(OwnsDefaultArg);
-    if (OwnsDefaultArg)
-      Record.AddStmt(D->getDefaultArgument());
+
+    Expr *OwnedDefaultArg = nullptr;
+    Decl const *InheritsFromDecl = nullptr;
+    if (D->hasDefaultArgument()) {
+      if (D->defaultArgumentWasInherited()) {
+        InheritsFromDecl = D->getDefaultArgStorage().getInheritedFrom();
+      } else {
+        OwnedDefaultArg = D->getDefaultArgument();
+      }
+    }
+
+    Record.push_back(OwnedDefaultArg != nullptr);
+    if (OwnedDefaultArg) {
+      Record.AddStmt(OwnedDefaultArg);
+    }
+    Record.push_back(InheritsFromDecl != nullptr);
+    if (InheritsFromDecl) {
+      Record.AddDeclRef(InheritsFromDecl);
+    }
+
     Code = serialization::DECL_NON_TYPE_TEMPLATE_PARM;
   }
 }
@@ -1618,11 +1646,26 @@
   } else {
     // Rest of TemplateTemplateParmDecl.
     Record.push_back(D->isParameterPack());
-    bool OwnsDefaultArg = D->hasDefaultArgument() &&
-                          !D->defaultArgumentWasInherited();
-    Record.push_back(OwnsDefaultArg);
-    if (OwnsDefaultArg)
-      Record.AddTemplateArgumentLoc(D->getDefaultArgument());
+
+    llvm::Optional<TemplateArgumentLoc> OwnedDefaultArg;
+    Decl const *InheritsFromDecl = nullptr;
+    if (D->hasDefaultArgument()) {
+      if (D->defaultArgumentWasInherited()) {
+        InheritsFromDecl = D->getDefaultArgStorage().getInheritedFrom();
+      } else {
+        OwnedDefaultArg = D->getDefaultArgument();
+      }
+    }
+
+    Record.push_back(OwnedDefaultArg.hasValue());
+    if (OwnedDefaultArg.hasValue()) {
+      Record.AddTemplateArgumentLoc(*OwnedDefaultArg);
+    }
+    Record.push_back(InheritsFromDecl != nullptr);
+    if (InheritsFromDecl) {
+      Record.AddDeclRef(InheritsFromDecl);
+    }
+
     Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
   }
 }
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -491,6 +491,12 @@
 
 } // namespace
 
+/// Inherit the default template argument from \p From to \p To. Returns
+/// \c false if there is no default template for \p From.
+template <typename ParmDecl>
+static bool inheritDefaultTemplateArgument(ASTContext &Context, ParmDecl *From,
+                                           Decl *ToD);
+
 template <typename DeclT>
 static llvm::iterator_range<MergedRedeclIterator<DeclT>>
 merged_redecls(DeclT *D) {
@@ -2337,6 +2343,11 @@
 
   if (Record.readInt())
     D->setDefaultArgument(GetTypeSourceInfo());
+
+  if (Record.readInt()) {
+    inheritDefaultTemplateArgument(
+        Reader.getContext(), Record.readDeclAs<TemplateTypeParmDecl>(), D);
+  }
 }
 
 void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
@@ -2354,8 +2365,14 @@
   } else {
     // Rest of NonTypeTemplateParmDecl.
     D->ParameterPack = Record.readInt();
+
     if (Record.readInt())
       D->setDefaultArgument(Record.readExpr());
+
+    if (Record.readInt()) {
+      inheritDefaultTemplateArgument(
+          Reader.getContext(), Record.readDeclAs<NonTypeTemplateParmDecl>(), D);
+    }
   }
 }
 
@@ -2372,9 +2389,16 @@
   } else {
     // Rest of TemplateTemplateParmDecl.
     D->ParameterPack = Record.readInt();
+
     if (Record.readInt())
       D->setDefaultArgument(Reader.getContext(),
                             Record.readTemplateArgumentLoc());
+
+    if (Record.readInt()) {
+      inheritDefaultTemplateArgument(
+          Reader.getContext(), Record.readDeclAs<TemplateTemplateParmDecl>(),
+          D);
+    }
   }
 }
 
@@ -3419,15 +3443,58 @@
   llvm_unreachable("attachPreviousDecl on non-redeclarable declaration");
 }
 
+/// Given some kind of a template parameter having a default argument, find the
+/// decl which actually provides the default argument, if inherited; otherwise,
+/// simply return \b D.
+template <typename ParmDecl>
+static ParmDecl const *getDefaultArgOwner(ParmDecl const *D,
+                                          unsigned MaxRecurse = 2) {
+  assert(D != nullptr && "getDefaultArgOwner on a null decl");
+  auto const &DA = D->getDefaultArgStorage();
+  assert(DA.isSet() && "getDefaultArgOwner on a decl with no default arg");
+  auto const *Prev = DA.getInheritedFrom();
+  if (Prev == nullptr || Prev == D) {
+    return D;
+  }
+  // Shouldn't have to pointer-chase too much, so we'll institute a limit of
+  // two dereferences:
+  // * one for the case where there's an inherited parameter, i.e. `DA`'s value
+  //   for `ValueOrInherited` is a `ParmDecl *`, which should always be the
+  //   owner of the default parameter;
+  // * one for the modules case, where `ValueOrInherited` is a `Chain *`, which
+  //   itself contains a pointer to a `ParmDecl *`.
+  assert(MaxRecurse && "too many levels of indirection, or inheritance cycle?");
+  return getDefaultArgOwner(Prev, MaxRecurse - 1);
+}
+
 /// Inherit the default template argument from \p From to \p To. Returns
 /// \c false if there is no default template for \p From.
 template <typename ParmDecl>
 static bool inheritDefaultTemplateArgument(ASTContext &Context, ParmDecl *From,
                                            Decl *ToD) {
-  auto *To = cast<ParmDecl>(ToD);
-  if (!From->hasDefaultArgument())
+  if (!From->hasDefaultArgument()) {
+    // Nothing to inherit; done.
     return false;
+  }
+
+  // Track down the owning decl, that is, the one which actually has the default
+  // arg, rather than one that might inherits it.  We'll inherit from the
+  // owner directly, and avoid what would be an indefinitely long chain of
+  // pointers.
+  From = const_cast<ParmDecl*>(getDefaultArgOwner(From));
+
+  auto *To = cast<ParmDecl>(ToD);
+  if (To->hasDefaultArgument() &&
+      getDefaultArgOwner(To) == From) {
+    // `To` already inherits from the same decl; done.
+    return true;
+  }
+
+  // Set up the inheritance info in `To`.  Note that this will result in a
+  // failed assertion if `To` already inherits from elsewhere, or `From` doesn't
+  // directly own that default arg.
   To->setInheritedDefaultArgument(Context, From);
+
   return true;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D38320: [... Steve O'Brien via Phabricator via cfe-commits

Reply via email to