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 +static bool inheritDefaultTemplateArgument(ASTContext &Context, ParmDecl *From, + Decl *ToD); + template static llvm::iterator_range> merged_redecls(DeclT *D) { @@ -2337,6 +2343,11 @@ if (Record.readInt()) D->setDefaultArgument(GetTypeSourceInfo()); + + if (Record.readInt()) { + inheritDefaultTemplateArgument( + Reader.getContext(), Record.readDeclAs(), 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(), 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(), + 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 +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 static bool inheritDefaultTemplateArgument(ASTContext &Context, ParmDecl *From, Decl *ToD) { - auto *To = cast(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(getDefaultArgOwner(From)); + + auto *To = cast(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 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 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 func1(T const &); + +template +int func1(T const &) { + return foo; +} + +// case 2: defaulted `TemplateTypeParmDecl`, non-defaulted 2nd tpl param +template +A func2(B const &); + +template +A func2(B const &) { + return A(20.0f); +} + +// case 3: defaulted `TemplateTemplateParmDecl`, non-defaulted 2nd tpl param +template +struct Container { T const &item; }; + +template