<div dir="ltr"><div dir="ltr">On Mon, 16 Nov 2020 at 18:49, David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Wed, Nov 11, 2020 at 3:08 PM Richard Smith via cfe-commits<br>
<<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br>
><br>
><br>
> Author: Richard Smith<br>
> Date: 2020-11-11T15:05:51-08:00<br>
> New Revision: e7f3e2103cdb567dda4fd52f81bf4bc07179f5a8<br>
><br>
> URL: <a href="https://github.com/llvm/llvm-project/commit/e7f3e2103cdb567dda4fd52f81bf4bc07179f5a8" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/e7f3e2103cdb567dda4fd52f81bf4bc07179f5a8</a><br>
> DIFF: <a href="https://github.com/llvm/llvm-project/commit/e7f3e2103cdb567dda4fd52f81bf4bc07179f5a8.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/e7f3e2103cdb567dda4fd52f81bf4bc07179f5a8.diff</a><br>
><br>
> LOG: Suppress printing template arguments that match default template<br>
> arguments of types by default.<br>
><br>
> This somewhat improves the worst-case printing of types like<br>
> std::string, std::vector, etc., where many irrelevant default arguments<br>
> can be included in the type as printed if we've lost the type sugar.<br>
<br>
"somewhat" - are there still some remaining challenges here? (I'd have<br>
thought this would be a significant improvement in these worst cases<br>
of lost type sugar)<br></blockquote><div><br></div><div>For std::vector, std::map, etc. we now print these types as-expected. But...</div><div><br></div><div>std::string is now printed as std::basic_string<char>, which, while an improvement, is still not the type name that we know a user would really want to see (similarly for std::string_view, and really any of the typedefs for std::basic_*). <a href="https://reviews.llvm.org/D91311">https://reviews.llvm.org/D91311</a> has a fix for that, but we're still in discussion as to whether that's the right interface for that functionality.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
> Added:<br>
>     clang/test/Misc/diag-template.cpp<br>
><br>
> Modified:<br>
>     clang/include/clang/AST/PrettyPrinter.h<br>
>     clang/include/clang/AST/Type.h<br>
>     clang/lib/AST/DeclTemplate.cpp<br>
>     clang/lib/AST/TypePrinter.cpp<br>
>     clang/lib/Frontend/FrontendActions.cpp<br>
>     clang/test/SemaCXX/cxx14-compat.cpp<br>
>     clang/test/SemaCXX/generic-selection.cpp<br>
>     clang/test/SemaTemplate/class-template-id.cpp<br>
>     clang/test/SemaTemplate/class-template-spec.cpp<br>
>     clang/test/SemaTemplate/instantiation-default-1.cpp<br>
><br>
> Removed:<br>
><br>
><br>
><br>
> ################################################################################<br>
> diff  --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h<br>
> index dfd5851bb30d..50e2142e2ef0 100644<br>
> --- a/clang/include/clang/AST/PrettyPrinter.h<br>
> +++ b/clang/include/clang/AST/PrettyPrinter.h<br>
> @@ -55,7 +55,8 @@ struct PrintingPolicy {<br>
>          SuppressInitializers(false), ConstantArraySizeAsWritten(false),<br>
>          AnonymousTagLocations(true), SuppressStrongLifetime(false),<br>
>          SuppressLifetimeQualifiers(false),<br>
> -        SuppressTemplateArgsInCXXConstructors(false), Bool(LO.Bool),<br>
> +        SuppressTemplateArgsInCXXConstructors(false),<br>
> +        SuppressDefaultTemplateArgs(true), Bool(LO.Bool),<br>
>          Nullptr(LO.CPlusPlus11), Restrict(LO.C99), Alignof(LO.CPlusPlus11),<br>
>          UnderscoreAlignof(LO.C11), UseVoidForZeroParams(!LO.CPlusPlus),<br>
>          SplitTemplateClosers(!LO.CPlusPlus11), TerseOutput(false),<br>
> @@ -167,6 +168,10 @@ struct PrintingPolicy {<br>
>    /// constructors.<br>
>    unsigned SuppressTemplateArgsInCXXConstructors : 1;<br>
><br>
> +  /// When true, attempt to suppress template arguments that match the default<br>
> +  /// argument for the parameter.<br>
> +  unsigned SuppressDefaultTemplateArgs : 1;<br>
> +<br>
>    /// Whether we can use 'bool' rather than '_Bool' (even if the language<br>
>    /// doesn't actually have 'bool', because, e.g., it is defined as a macro).<br>
>    unsigned Bool : 1;<br>
><br>
> diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h<br>
> index 1442bc740620..6dedd097ff89 100644<br>
> --- a/clang/include/clang/AST/Type.h<br>
> +++ b/clang/include/clang/AST/Type.h<br>
> @@ -61,6 +61,7 @@ class ExtQuals;<br>
>  class QualType;<br>
>  class ConceptDecl;<br>
>  class TagDecl;<br>
> +class TemplateParameterList;<br>
>  class Type;<br>
><br>
>  enum {<br>
> @@ -5196,15 +5197,18 @@ class alignas(8) TemplateSpecializationType<br>
>  /// enclosing the template arguments.<br>
>  void printTemplateArgumentList(raw_ostream &OS,<br>
>                                 ArrayRef<TemplateArgument> Args,<br>
> -                               const PrintingPolicy &Policy);<br>
> +                               const PrintingPolicy &Policy,<br>
> +                               const TemplateParameterList *TPL = nullptr);<br>
><br>
>  void printTemplateArgumentList(raw_ostream &OS,<br>
>                                 ArrayRef<TemplateArgumentLoc> Args,<br>
> -                               const PrintingPolicy &Policy);<br>
> +                               const PrintingPolicy &Policy,<br>
> +                               const TemplateParameterList *TPL = nullptr);<br>
><br>
>  void printTemplateArgumentList(raw_ostream &OS,<br>
>                                 const TemplateArgumentListInfo &Args,<br>
> -                               const PrintingPolicy &Policy);<br>
> +                               const PrintingPolicy &Policy,<br>
> +                               const TemplateParameterList *TPL = nullptr);<br>
><br>
>  /// The injected class name of a C++ class template or class<br>
>  /// template partial specialization.  Used to record that a type was<br>
><br>
> diff  --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp<br>
> index 9918377070c3..328ceaa63df3 100644<br>
> --- a/clang/lib/AST/DeclTemplate.cpp<br>
> +++ b/clang/lib/AST/DeclTemplate.cpp<br>
> @@ -914,10 +914,14 @@ void ClassTemplateSpecializationDecl::getNameForDiagnostic(<br>
>    const auto *PS = dyn_cast<ClassTemplatePartialSpecializationDecl>(this);<br>
>    if (const ASTTemplateArgumentListInfo *ArgsAsWritten =<br>
>            PS ? PS->getTemplateArgsAsWritten() : nullptr) {<br>
> -    printTemplateArgumentList(OS, ArgsAsWritten->arguments(), Policy);<br>
> +    printTemplateArgumentList(<br>
> +        OS, ArgsAsWritten->arguments(), Policy,<br>
> +        getSpecializedTemplate()->getTemplateParameters());<br>
>    } else {<br>
>      const TemplateArgumentList &TemplateArgs = getTemplateArgs();<br>
> -    printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy);<br>
> +    printTemplateArgumentList(<br>
> +        OS, TemplateArgs.asArray(), Policy,<br>
> +        getSpecializedTemplate()->getTemplateParameters());<br>
>    }<br>
>  }<br>
><br>
> @@ -1261,10 +1265,14 @@ void VarTemplateSpecializationDecl::getNameForDiagnostic(<br>
>    const auto *PS = dyn_cast<VarTemplatePartialSpecializationDecl>(this);<br>
>    if (const ASTTemplateArgumentListInfo *ArgsAsWritten =<br>
>            PS ? PS->getTemplateArgsAsWritten() : nullptr) {<br>
> -    printTemplateArgumentList(OS, ArgsAsWritten->arguments(), Policy);<br>
> +    printTemplateArgumentList(<br>
> +        OS, ArgsAsWritten->arguments(), Policy,<br>
> +        getSpecializedTemplate()->getTemplateParameters());<br>
>    } else {<br>
>      const TemplateArgumentList &TemplateArgs = getTemplateArgs();<br>
> -    printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy);<br>
> +    printTemplateArgumentList(<br>
> +        OS, TemplateArgs.asArray(), Policy,<br>
> +        getSpecializedTemplate()->getTemplateParameters());<br>
>    }<br>
>  }<br>
><br>
><br>
> diff  --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp<br>
> index 5e9b22664185..3368905007a4 100644<br>
> --- a/clang/lib/AST/TypePrinter.cpp<br>
> +++ b/clang/lib/AST/TypePrinter.cpp<br>
> @@ -1124,7 +1124,9 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {<br>
>        OS << T->getTypeConstraintConcept()->getName();<br>
>        auto Args = T->getTypeConstraintArguments();<br>
>        if (!Args.empty())<br>
> -        printTemplateArgumentList(OS, Args, Policy);<br>
> +        printTemplateArgumentList(<br>
> +            OS, Args, Policy,<br>
> +            T->getTypeConstraintConcept()->getTemplateParameters());<br>
>        OS << ' ';<br>
>      }<br>
>      switch (T->getKeyword()) {<br>
> @@ -1226,7 +1228,9 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {<br>
>      IncludeStrongLifetimeRAII Strong(Policy);<br>
>      OS << Spec->getIdentifier()->getName();<br>
>      const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();<br>
> -    printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy);<br>
> +    printTemplateArgumentList(<br>
> +        OS, TemplateArgs.asArray(), Policy,<br>
> +        Spec->getSpecializedTemplate()->getTemplateParameters());<br>
>      OS << "::";<br>
>    } else if (const auto *Tag = dyn_cast<TagDecl>(DC)) {<br>
>      if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())<br>
> @@ -1317,7 +1321,9 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {<br>
>        Args = TemplateArgs.asArray();<br>
>      }<br>
>      IncludeStrongLifetimeRAII Strong(Policy);<br>
> -    printTemplateArgumentList(OS, Args, Policy);<br>
> +    printTemplateArgumentList(<br>
> +        OS, Args, Policy,<br>
> +        Spec->getSpecializedTemplate()->getTemplateParameters());<br>
>    }<br>
><br>
>    spaceBeforePlaceHolder(OS);<br>
> @@ -1389,7 +1395,11 @@ void TypePrinter::printTemplateSpecializationBefore(<br>
>    IncludeStrongLifetimeRAII Strong(Policy);<br>
>    T->getTemplateName().print(OS, Policy);<br>
><br>
> -  printTemplateArgumentList(OS, T->template_arguments(), Policy);<br>
> +  const TemplateParameterList *TPL = nullptr;<br>
> +  if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl())<br>
> +    TPL = TD->getTemplateParameters();<br>
> +<br>
> +  printTemplateArgumentList(OS, T->template_arguments(), Policy, TPL);<br>
>    spaceBeforePlaceHolder(OS);<br>
>  }<br>
><br>
> @@ -1789,9 +1799,159 @@ static void printArgument(const TemplateArgumentLoc &A,<br>
>    return A.getArgument().print(PP, OS);<br>
>  }<br>
><br>
> +static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,<br>
> +                                          TemplateArgument Pattern,<br>
> +                                          ArrayRef<TemplateArgument> Args,<br>
> +                                          unsigned Depth);<br>
> +<br>
> +static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,<br>
> +                              ArrayRef<TemplateArgument> Args, unsigned Depth) {<br>
> +  if (Ctx.hasSameType(T, Pattern))<br>
> +    return true;<br>
> +<br>
> +  // A type parameter matches its argument.<br>
> +  if (auto *TTPT = Pattern->getAs<TemplateTypeParmType>()) {<br>
> +    if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() &&<br>
> +        Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) {<br>
> +      QualType SubstArg = Ctx.getQualifiedType(<br>
> +          Args[TTPT->getIndex()].getAsType(), Pattern.getQualifiers());<br>
> +      return Ctx.hasSameType(SubstArg, T);<br>
> +    }<br>
> +    return false;<br>
> +  }<br>
> +<br>
> +  // FIXME: Recurse into array types.<br>
> +<br>
> +  // All other cases will need the types to be identically qualified.<br>
> +  Qualifiers TQual, PatQual;<br>
> +  T = Ctx.getUnqualifiedArrayType(T, TQual);<br>
> +  Pattern = Ctx.getUnqualifiedArrayType(Pattern, PatQual);<br>
> +  if (TQual != PatQual)<br>
> +    return false;<br>
> +<br>
> +  // Recurse into pointer-like types.<br>
> +  {<br>
> +    QualType TPointee = T->getPointeeType();<br>
> +    QualType PPointee = Pattern->getPointeeType();<br>
> +    if (!TPointee.isNull() && !PPointee.isNull())<br>
> +      return T->getTypeClass() == Pattern->getTypeClass() &&<br>
> +             isSubstitutedType(Ctx, TPointee, PPointee, Args, Depth);<br>
> +  }<br>
> +<br>
> +  // Recurse into template specialization types.<br>
> +  if (auto *PTST =<br>
> +          Pattern.getCanonicalType()->getAs<TemplateSpecializationType>()) {<br>
> +    TemplateName Template;<br>
> +    ArrayRef<TemplateArgument> TemplateArgs;<br>
> +    if (auto *TTST = T->getAs<TemplateSpecializationType>()) {<br>
> +      Template = TTST->getTemplateName();<br>
> +      TemplateArgs = TTST->template_arguments();<br>
> +    } else if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(<br>
> +                   T->getAsCXXRecordDecl())) {<br>
> +      Template = TemplateName(CTSD->getSpecializedTemplate());<br>
> +      TemplateArgs = CTSD->getTemplateArgs().asArray();<br>
> +    } else {<br>
> +      return false;<br>
> +    }<br>
> +<br>
> +    if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),<br>
> +                                       Args, Depth))<br>
> +      return false;<br>
> +    if (TemplateArgs.size() != PTST->getNumArgs())<br>
> +      return false;<br>
> +    for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)<br>
> +      if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PTST->getArg(I),<br>
> +                                         Args, Depth))<br>
> +        return false;<br>
> +    return true;<br>
> +  }<br>
> +<br>
> +  // FIXME: Handle more cases.<br>
> +  return false;<br>
> +}<br>
> +<br>
> +static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,<br>
> +                                          TemplateArgument Pattern,<br>
> +                                          ArrayRef<TemplateArgument> Args,<br>
> +                                          unsigned Depth) {<br>
> +  Arg = Ctx.getCanonicalTemplateArgument(Arg);<br>
> +  Pattern = Ctx.getCanonicalTemplateArgument(Pattern);<br>
> +  if (Arg.structurallyEquals(Pattern))<br>
> +    return true;<br>
> +<br>
> +  if (Pattern.getKind() == TemplateArgument::Expression) {<br>
> +    if (auto *DRE =<br>
> +            dyn_cast<DeclRefExpr>(Pattern.getAsExpr()->IgnoreParenImpCasts())) {<br>
> +      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))<br>
> +        return NTTP->getDepth() == Depth && Args.size() > NTTP->getIndex() &&<br>
> +               Args[NTTP->getIndex()].structurallyEquals(Arg);<br>
> +    }<br>
> +  }<br>
> +<br>
> +  if (Arg.getKind() != Pattern.getKind())<br>
> +    return false;<br>
> +<br>
> +  if (Arg.getKind() == TemplateArgument::Type)<br>
> +    return isSubstitutedType(Ctx, Arg.getAsType(), Pattern.getAsType(), Args,<br>
> +                             Depth);<br>
> +<br>
> +  if (Arg.getKind() == TemplateArgument::Template) {<br>
> +    TemplateDecl *PatTD = Pattern.getAsTemplate().getAsTemplateDecl();<br>
> +    if (auto *TTPD = dyn_cast_or_null<TemplateTemplateParmDecl>(PatTD))<br>
> +      return TTPD->getDepth() == Depth && Args.size() > TTPD->getIndex() &&<br>
> +             Ctx.getCanonicalTemplateArgument(Args[TTPD->getIndex()])<br>
> +                 .structurallyEquals(Arg);<br>
> +  }<br>
> +<br>
> +  // FIXME: Handle more cases.<br>
> +  return false;<br>
> +}<br>
> +<br>
> +/// Make a best-effort determination of whether the type T can be produced by<br>
> +/// substituting Args into the default argument of Param.<br>
> +static bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,<br>
> +                                         const NamedDecl *Param,<br>
> +                                         ArrayRef<TemplateArgument> Args,<br>
> +                                         unsigned Depth) {<br>
> +  // An empty pack is equivalent to not providing a pack argument.<br>
> +  if (Arg.getKind() == TemplateArgument::Pack && Arg.pack_size() == 0)<br>
> +    return true;<br>
> +<br>
> +  if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Param)) {<br>
> +    return TTPD->hasDefaultArgument() &&<br>
> +           isSubstitutedTemplateArgument(Ctx, Arg, TTPD->getDefaultArgument(),<br>
> +                                         Args, Depth);<br>
> +  } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {<br>
> +    return TTPD->hasDefaultArgument() &&<br>
> +           isSubstitutedTemplateArgument(<br>
> +               Ctx, Arg, TTPD->getDefaultArgument().getArgument(), Args, Depth);<br>
> +  } else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param)) {<br>
> +    return NTTPD->hasDefaultArgument() &&<br>
> +           isSubstitutedTemplateArgument(Ctx, Arg, NTTPD->getDefaultArgument(),<br>
> +                                         Args, Depth);<br>
> +  }<br>
> +  return false;<br>
> +}<br>
> +<br>
>  template<typename TA><br>
>  static void printTo(raw_ostream &OS, ArrayRef<TA> Args,<br>
> -                    const PrintingPolicy &Policy, bool SkipBrackets) {<br>
> +                    const PrintingPolicy &Policy, bool SkipBrackets,<br>
> +                    const TemplateParameterList *TPL) {<br>
> +  // Drop trailing template arguments that match default arguments.<br>
> +  if (TPL && Policy.SuppressDefaultTemplateArgs &&<br>
> +      !Policy.PrintCanonicalTypes && !Args.empty() &&<br>
> +      Args.size() <= TPL->size()) {<br>
> +    ASTContext &Ctx = TPL->getParam(0)->getASTContext();<br>
> +    llvm::SmallVector<TemplateArgument, 8> OrigArgs;<br>
> +    for (const TA &A : Args)<br>
> +      OrigArgs.push_back(getArgument(A));<br>
> +    while (!Args.empty() &&<br>
> +           isSubstitutedDefaultArgument(Ctx, getArgument(Args.back()),<br>
> +                                        TPL->getParam(Args.size() - 1),<br>
> +                                        OrigArgs, TPL->getDepth()))<br>
> +      Args = Args.drop_back();<br>
> +  }<br>
> +<br>
>    const char *Comma = Policy.MSVCFormatting ? "," : ", ";<br>
>    if (!SkipBrackets)<br>
>      OS << '<';<br>
> @@ -1806,7 +1966,7 @@ static void printTo(raw_ostream &OS, ArrayRef<TA> Args,<br>
>      if (Argument.getKind() == TemplateArgument::Pack) {<br>
>        if (Argument.pack_size() && !FirstArg)<br>
>          OS << Comma;<br>
> -      printTo(ArgOS, Argument.getPackAsArray(), Policy, true);<br>
> +      printTo(ArgOS, Argument.getPackAsArray(), Policy, true, nullptr);<br>
>      } else {<br>
>        if (!FirstArg)<br>
>          OS << Comma;<br>
> @@ -1839,20 +1999,23 @@ static void printTo(raw_ostream &OS, ArrayRef<TA> Args,<br>
><br>
>  void clang::printTemplateArgumentList(raw_ostream &OS,<br>
>                                        const TemplateArgumentListInfo &Args,<br>
> -                                      const PrintingPolicy &Policy) {<br>
> -  return printTo(OS, Args.arguments(), Policy, false);<br>
> +                                      const PrintingPolicy &Policy,<br>
> +                                      const TemplateParameterList *TPL) {<br>
> +  printTemplateArgumentList(OS, Args.arguments(), Policy, TPL);<br>
>  }<br>
><br>
>  void clang::printTemplateArgumentList(raw_ostream &OS,<br>
>                                        ArrayRef<TemplateArgument> Args,<br>
> -                                      const PrintingPolicy &Policy) {<br>
> -  printTo(OS, Args, Policy, false);<br>
> +                                      const PrintingPolicy &Policy,<br>
> +                                      const TemplateParameterList *TPL) {<br>
> +  printTo(OS, Args, Policy, false, TPL);<br>
>  }<br>
><br>
>  void clang::printTemplateArgumentList(raw_ostream &OS,<br>
>                                        ArrayRef<TemplateArgumentLoc> Args,<br>
> -                                      const PrintingPolicy &Policy) {<br>
> -  printTo(OS, Args, Policy, false);<br>
> +                                      const PrintingPolicy &Policy,<br>
> +                                      const TemplateParameterList *TPL) {<br>
> +  printTo(OS, Args, Policy, false, TPL);<br>
>  }<br>
><br>
>  std::string Qualifiers::getAsString() const {<br>
><br>
> diff  --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp<br>
> index 0993e5eb033f..f38da54cebcc 100644<br>
> --- a/clang/lib/Frontend/FrontendActions.cpp<br>
> +++ b/clang/lib/Frontend/FrontendActions.cpp<br>
> @@ -467,7 +467,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {<br>
>      Entry.Event = BeginInstantiation ? "Begin" : "End";<br>
>      if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) {<br>
>        llvm::raw_string_ostream OS(Entry.Name);<br>
> -      NamedTemplate->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);<br>
> +      PrintingPolicy Policy = TheSema.Context.getPrintingPolicy();<br>
> +      // FIXME: Also ask for FullyQualifiedNames?<br>
> +      Policy.SuppressDefaultTemplateArgs = false;<br>
> +      NamedTemplate->getNameForDiagnostic(OS, Policy, true);<br>
>        const PresumedLoc DefLoc =<br>
>          TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation());<br>
>        if(!DefLoc.isInvalid())<br>
><br>
> diff  --git a/clang/test/Misc/diag-template.cpp b/clang/test/Misc/diag-template.cpp<br>
> new file mode 100644<br>
> index 000000000000..30d4829409bb<br>
> --- /dev/null<br>
> +++ b/clang/test/Misc/diag-template.cpp<br>
> @@ -0,0 +1,37 @@<br>
> +// RUN: %clang_cc1 -verify %s<br>
> +<br>
> +namespace default_args {<br>
> +  template<typename T> struct char_traits;<br>
> +  template<typename T> struct allocator;<br>
> +  template<typename T, typename = char_traits<T>, typename = allocator<T>> struct basic_string {};<br>
> +<br>
> +  typedef basic_string<char> string;<br>
> +<br>
> +  template<typename T> T f(T);<br>
> +<br>
> +  void test1() {<br>
> +    string s;<br>
> +    f(s).size(); // expected-error {{no member named 'size' in 'default_args::basic_string<char>'}}<br>
> +  }<br>
> +<br>
> +  template<typename T> struct default_delete {};<br>
> +  template<class T, class Deleter = default_delete<T>> class unique_ptr {};<br>
> +  template<class T, class Deleter> class unique_ptr<T[], Deleter> {};<br>
> +  void test2() {<br>
> +    unique_ptr<string> ups;<br>
> +    f(ups).reset(); // expected-error {{no member named 'reset' in 'default_args::unique_ptr<default_args::basic_string<char>>'}}<br>
> +  }<br>
> +<br>
> +  template<int A, int B = A> struct Z { int error[B]; }; // expected-error {{negative size}}<br>
> +  Z<-1> z; // expected-note {{in instantiation of template class 'default_args::Z<-1>' requested here}}<br>
> +<br>
> +  template<template<typename> class A = allocator, template<typename> class B = A> struct Q {};<br>
> +  void test3() {<br>
> +    f(Q<>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<>'}}<br>
> +    f(Q<allocator>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<>'}}<br>
> +    f(Q<allocator, allocator>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<>'}}<br>
> +    f(Q<char_traits>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<char_traits>'}}<br>
> +    f(Q<char_traits, char_traits>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<char_traits>'}}<br>
> +    f(Q<char_traits, allocator>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<char_traits, allocator>'}}<br>
> +  }<br>
> +}<br>
><br>
> diff  --git a/clang/test/SemaCXX/cxx14-compat.cpp b/clang/test/SemaCXX/cxx14-compat.cpp<br>
> index d70f477cd09a..d6396a7de4df 100644<br>
> --- a/clang/test/SemaCXX/cxx14-compat.cpp<br>
> +++ b/clang/test/SemaCXX/cxx14-compat.cpp<br>
> @@ -16,7 +16,7 @@ namespace [[]] NS_with_attr {} // expected-warning {{incompatible with C++ stand<br>
>  enum { e [[]] }; // expected-warning {{incompatible with C++ standards before C++17}}<br>
><br>
>  template<typename T = int> struct X {};<br>
> -X x; // expected-warning {{class template argument deduction is incompatible with C++ standards before C++17; for compatibility, use explicit type name 'X<int>'}}<br>
> +X x; // expected-warning {{class template argument deduction is incompatible with C++ standards before C++17; for compatibility, use explicit type name 'X<>'}}<br>
><br>
>  template<template<typename> class> struct Y {};<br>
>  Y<X> yx; // ok, not class template argument deduction<br>
><br>
> diff  --git a/clang/test/SemaCXX/generic-selection.cpp b/clang/test/SemaCXX/generic-selection.cpp<br>
> index c0a5d89fff67..8bf4a784f9bf 100644<br>
> --- a/clang/test/SemaCXX/generic-selection.cpp<br>
> +++ b/clang/test/SemaCXX/generic-selection.cpp<br>
> @@ -14,7 +14,7 @@ static_assert(A<int>::id == 1, "fail");<br>
>  static_assert(A<float>::id == 2, "fail");<br>
>  static_assert(A<double, double>::id == 3, "fail");<br>
><br>
> -A<char> a1; // expected-note {{in instantiation of template class 'A<char, void *>' requested here}}<br>
> +A<char> a1; // expected-note {{in instantiation of template class 'A<char>' requested here}}<br>
>  A<short, int> a2; // expected-note {{in instantiation of template class 'A<short, int>' requested here}}<br>
><br>
>  template <typename T, typename U><br>
><br>
> diff  --git a/clang/test/SemaTemplate/class-template-id.cpp b/clang/test/SemaTemplate/class-template-id.cpp<br>
> index 50cb3ef59ea4..b32a03e478d9 100644<br>
> --- a/clang/test/SemaTemplate/class-template-id.cpp<br>
> +++ b/clang/test/SemaTemplate/class-template-id.cpp<br>
> @@ -9,9 +9,9 @@ A<int, FLOAT> *foo(A<int> *ptr, A<int> const *ptr2, A<int, double> *ptr3) {<br>
>    if (ptr)<br>
>      return ptr; // okay<br>
>    else if (ptr2)<br>
> -    return ptr2; // expected-error{{cannot initialize return object of type 'A<int, FLOAT> *' (aka 'A<int, float> *') with an lvalue of type 'const A<int> *'}}<br>
> +    return ptr2; // expected-error{{cannot initialize return object of type 'A<int> *' with an lvalue of type 'const A<int> *'}}<br>
>    else {<br>
> -    return ptr3; // expected-error{{cannot initialize return object of type 'A<int, FLOAT> *' (aka 'A<int, float> *') with an lvalue of type 'A<int, double> *'}}<br>
> +    return ptr3; // expected-error{{cannot initialize return object of type 'A<int> *' with an lvalue of type 'A<int, double> *'}}<br>
>    }<br>
>  }<br>
><br>
><br>
> diff  --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp<br>
> index d763944371cc..e96ef44b7a25 100644<br>
> --- a/clang/test/SemaTemplate/class-template-spec.cpp<br>
> +++ b/clang/test/SemaTemplate/class-template-spec.cpp<br>
> @@ -22,7 +22,7 @@ int test_incomplete_specs(A<double, double> *a1,<br>
>                            A<double> *a2)<br>
>  {<br>
>    (void)a1->x; // expected-error{{member access into incomplete type}}<br>
> -  (void)a2->x; // expected-error{{implicit instantiation of undefined template 'A<double, int>'}}<br>
> +  (void)a2->x; // expected-error{{implicit instantiation of undefined template 'A<double>'}}<br>
>  }<br>
><br>
>  typedef float FLOAT;<br>
><br>
> diff  --git a/clang/test/SemaTemplate/instantiation-default-1.cpp b/clang/test/SemaTemplate/instantiation-default-1.cpp<br>
> index ab9eca75e239..33e01b6b8aa5 100644<br>
> --- a/clang/test/SemaTemplate/instantiation-default-1.cpp<br>
> +++ b/clang/test/SemaTemplate/instantiation-default-1.cpp<br>
> @@ -36,7 +36,7 @@ typedef int& int_ref_t;<br>
>  Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}<br>
><br>
><br>
> -template<> struct Def1<const int> { }; // expected-error{{redefinition of 'Def1<const int, const int>'}}<br>
> +template<> struct Def1<const int> { }; // expected-error{{redefinition of 'Def1<const int>'}}<br>
><br>
>  template<typename T, typename T2 = T&> struct Def3;<br>
><br>
><br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div>