Page MenuHomePhabricator

D38320.diff
No OneTemporary

File Metadata

Created
Jan 24 2020, 4:30 PM

D38320.diff

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;
}
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: 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

Event Timeline