diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -223,7 +223,8 @@ if (TTPD->hasDefaultArgument()) { P.Default.emplace(); llvm::raw_string_ostream Out(*P.Default); - TTPD->getDefaultArgument().getArgument().print(PP, Out); + TTPD->getDefaultArgument().getArgument().print(PP, Out, + /*IncludeType*/ false); } } TempParameters.push_back(std::move(P)); diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -204,6 +204,9 @@ bool OmitTemplateKW = false) const; void print(raw_ostream &Out, const ASTContext &Context, const PrintingPolicy &Policy, bool OmitTemplateKW = false) const; + + static bool shouldIncludeTypeForArgument(const TemplateParameterList *TPL, + unsigned Idx); }; /// Stores a list of template parameters and the associated diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1615,6 +1615,8 @@ return T->getStmtClass() == CharacterLiteralClass; } + static void print(unsigned val, CharacterKind Kind, raw_ostream &OS); + // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); diff --git a/clang/include/clang/AST/StmtDataCollectors.td b/clang/include/clang/AST/StmtDataCollectors.td --- a/clang/include/clang/AST/StmtDataCollectors.td +++ b/clang/include/clang/AST/StmtDataCollectors.td @@ -51,7 +51,7 @@ // Print all template arguments into ArgString llvm::raw_string_ostream OS(ArgString); for (unsigned i = 0; i < Args->size(); ++i) { - Args->get(i).print(Context.getLangOpts(), OS); + Args->get(i).print(Context.getLangOpts(), OS, /*IncludeType*/ true); // Add a padding character so that 'foo()' != 'foo()'. OS << '\n'; } diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -389,7 +389,8 @@ TemplateArgument getPackExpansionPattern() const; /// Print this template argument to the given output stream. - void print(const PrintingPolicy &Policy, raw_ostream &Out) const; + void print(const PrintingPolicy &Policy, raw_ostream &Out, + bool IncludeType) const; /// Debugging aid that dumps the template argument. void dump(raw_ostream &Out) const; diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -140,9 +140,9 @@ void DynTypedNode::print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const { if (const TemplateArgument *TA = get()) - TA->print(PP, OS); + TA->print(PP, OS, /*IncludeType*/ true); else if (const TemplateArgumentLoc *TAL = get()) - TAL->getArgument().print(PP, OS); + TAL->getArgument().print(PP, OS, /*IncludeType*/ true); else if (const TemplateName *TN = get()) TN->print(OS, PP); else if (const NestedNameSpecifier *NNS = get()) diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -110,8 +110,12 @@ void printTemplateParameters(const TemplateParameterList *Params, bool OmitTemplateKW = false); - void printTemplateArguments(llvm::ArrayRef Args); - void printTemplateArguments(llvm::ArrayRef Args); + void printTemplateArguments(llvm::ArrayRef Args, + const TemplateParameterList *Params, + bool TemplOverloaded); + void printTemplateArguments(llvm::ArrayRef Args, + const TemplateParameterList *Params, + bool TemplOverloaded); void prettyPrintAttributes(Decl *D); void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); @@ -644,11 +648,16 @@ llvm::raw_string_ostream POut(Proto); DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation); const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten(); + const TemplateParameterList *TPL = D->getTemplateSpecializationInfo() + ->getTemplate() + ->getTemplateParameters(); if (TArgAsWritten && !Policy.PrintCanonicalTypes) - TArgPrinter.printTemplateArguments(TArgAsWritten->arguments()); + TArgPrinter.printTemplateArguments(TArgAsWritten->arguments(), TPL, + /*TemplOverloaded*/ true); else if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) - TArgPrinter.printTemplateArguments(TArgs->asArray()); + TArgPrinter.printTemplateArguments(TArgs->asArray(), TPL, + /*TemplOverloaded*/ true); } QualType Ty = D->getType(); @@ -988,7 +997,9 @@ if (const auto *TST = dyn_cast(TSI->getType())) Args = TST->template_arguments(); - printTemplateArguments(Args); + printTemplateArguments( + Args, S->getSpecializedTemplate()->getTemplateParameters(), + /*TemplOverloaded*/ false); } } @@ -1080,22 +1091,36 @@ Out << ' '; } -void DeclPrinter::printTemplateArguments(ArrayRef Args) { +void DeclPrinter::printTemplateArguments(ArrayRef Args, + const TemplateParameterList *Params, + bool TemplOverloaded) { Out << "<"; for (size_t I = 0, E = Args.size(); I < E; ++I) { if (I) Out << ", "; - Args[I].print(Policy, Out); + if (TemplOverloaded || !Params) + Args[I].print(Policy, Out, /*IncludeType*/ true); + else + Args[I].print( + Policy, Out, + TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); } Out << ">"; } -void DeclPrinter::printTemplateArguments(ArrayRef Args) { +void DeclPrinter::printTemplateArguments(ArrayRef Args, + const TemplateParameterList *Params, + bool TemplOverloaded) { Out << "<"; for (size_t I = 0, E = Args.size(); I < E; ++I) { if (I) Out << ", "; - Args[I].getArgument().print(Policy, Out); + if (TemplOverloaded) + Args[I].getArgument().print(Policy, Out, /*IncludeType*/ true); + else + Args[I].getArgument().print( + Policy, Out, + TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); } Out << ">"; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -167,6 +167,18 @@ return HasRequiresClause || HasConstrainedParameters; } +bool TemplateParameterList::shouldIncludeTypeForArgument( + const TemplateParameterList *TPL, unsigned Idx) { + if (!TPL || Idx >= TPL->size()) + return true; + const NamedDecl *TemplParam = TPL->getParam(Idx); + if (const auto *ParamValueDecl = + dyn_cast(TemplParam)) + if (ParamValueDecl->getType()->getContainedDeducedType()) + return true; + return false; +} + namespace clang { void *allocateDefaultArgStorageChain(const ASTContext &C) { @@ -1420,8 +1432,9 @@ ConceptName.printName(OS, Policy); if (hasExplicitTemplateArgs()) { OS << "<"; + // FIXME: Find corresponding parameter for argument for (auto &ArgLoc : ArgsAsWritten->arguments()) - ArgLoc.getArgument().print(Policy, OS); + ArgLoc.getArgument().print(Policy, OS, /*IncludeType*/ false); OS << ">"; } } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -32,6 +32,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -705,7 +706,9 @@ StringRef Param = Params->getParam(i)->getName(); if (Param.empty()) continue; TOut << Param << " = "; - Args.get(i).print(Policy, TOut); + Args.get(i).print( + Policy, TOut, + TemplateParameterList::shouldIncludeTypeForArgument(Params, i)); TOut << ", "; } } @@ -721,7 +724,7 @@ StringRef Param = Params->getParam(i)->getName(); if (Param.empty()) continue; TOut << Param << " = "; - Args->get(i).print(Policy, TOut); + Args->get(i).print(Policy, TOut, /*IncludeType*/ true); TOut << ", "; } } @@ -865,6 +868,76 @@ return std::string(S.str()); } +void CharacterLiteral::print(unsigned Val, CharacterKind Kind, + raw_ostream &OS) { + switch (Kind) { + case CharacterLiteral::Ascii: + break; // no prefix. + case CharacterLiteral::Wide: + OS << 'L'; + break; + case CharacterLiteral::UTF8: + OS << "u8"; + break; + case CharacterLiteral::UTF16: + OS << 'u'; + break; + case CharacterLiteral::UTF32: + OS << 'U'; + break; + } + + switch (Val) { + case '\\': + OS << "'\\\\'"; + break; + case '\'': + OS << "'\\''"; + break; + case '\a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + OS << "'\\a'"; + break; + case '\b': + OS << "'\\b'"; + break; + // Nonstandard escape sequence. + /*case '\e': + OS << "'\\e'"; + break;*/ + case '\f': + OS << "'\\f'"; + break; + case '\n': + OS << "'\\n'"; + break; + case '\r': + OS << "'\\r'"; + break; + case '\t': + OS << "'\\t'"; + break; + case '\v': + OS << "'\\v'"; + break; + default: + // A character literal might be sign-extended, which + // would result in an invalid \U escape sequence. + // FIXME: multicharacter literals such as '\xFF\xFF\xFF\xFF' + // are not correctly handled. + if ((Val & ~0xFFu) == ~0xFFu && Kind == CharacterLiteral::Ascii) + Val &= 0xFFu; + if (Val < 256 && isPrintable((unsigned char)Val)) + OS << "'" << (char)Val << "'"; + else if (Val < 256) + OS << "'\\x" << llvm::format("%02x", Val) << "'"; + else if (Val <= 0xFFFF) + OS << "'\\u" << llvm::format("%04x", Val) << "'"; + else + OS << "'\\U" << llvm::format("%08x", Val) << "'"; + } +} + FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary), Loc(L) { diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -288,8 +288,9 @@ if (ResolveTemplateArguments && Record) { // Print the type trait with resolved template parameters. Record->printName(OS); - printTemplateArgumentList(OS, Record->getTemplateArgs().asArray(), - Policy); + printTemplateArgumentList( + OS, Record->getTemplateArgs().asArray(), Policy, + Record->getSpecializedTemplate()->getTemplateParameters()); break; } const Type *T = getAsType(); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -51,7 +51,6 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -1003,8 +1002,13 @@ if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); - if (Node->hasExplicitTemplateArgs()) - printTemplateArgumentList(OS, Node->template_arguments(), Policy); + if (Node->hasExplicitTemplateArgs()) { + const TemplateParameterList *TPL = nullptr; + if (!Node->hadMultipleCandidates()) + if (auto *TD = dyn_cast(Node->getDecl())) + TPL = TD->getTemplateParameters(); + printTemplateArgumentList(OS, Node->template_arguments(), Policy, TPL); + } } void StmtPrinter::VisitDependentScopeDeclRefExpr( @@ -1082,65 +1086,7 @@ } void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { - unsigned value = Node->getValue(); - - switch (Node->getKind()) { - case CharacterLiteral::Ascii: break; // no prefix. - case CharacterLiteral::Wide: OS << 'L'; break; - case CharacterLiteral::UTF8: OS << "u8"; break; - case CharacterLiteral::UTF16: OS << 'u'; break; - case CharacterLiteral::UTF32: OS << 'U'; break; - } - - switch (value) { - case '\\': - OS << "'\\\\'"; - break; - case '\'': - OS << "'\\''"; - break; - case '\a': - // TODO: K&R: the meaning of '\\a' is different in traditional C - OS << "'\\a'"; - break; - case '\b': - OS << "'\\b'"; - break; - // Nonstandard escape sequence. - /*case '\e': - OS << "'\\e'"; - break;*/ - case '\f': - OS << "'\\f'"; - break; - case '\n': - OS << "'\\n'"; - break; - case '\r': - OS << "'\\r'"; - break; - case '\t': - OS << "'\\t'"; - break; - case '\v': - OS << "'\\v'"; - break; - default: - // A character literal might be sign-extended, which - // would result in an invalid \U escape sequence. - // FIXME: multicharacter literals such as '\xFF\xFF\xFF\xFF' - // are not correctly handled. - if ((value & ~0xFFu) == ~0xFFu && Node->getKind() == CharacterLiteral::Ascii) - value &= 0xFFu; - if (value < 256 && isPrintable((unsigned char)value)) - OS << "'" << (char)value << "'"; - else if (value < 256) - OS << "'\\x" << llvm::format("%02x", value) << "'"; - else if (value <= 0xFFFF) - OS << "'\\u" << llvm::format("%04x", value) << "'"; - else - OS << "'\\U" << llvm::format("%08x", value) << "'"; - } + CharacterLiteral::print(Node->getValue(), Node->getKind(), OS); } /// Prints the given expression using the original source text. Returns true on @@ -1466,8 +1412,16 @@ if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); + const TemplateParameterList *TPL = nullptr; + if (auto *FD = dyn_cast(Node->getMemberDecl())) { + if (!Node->hadMultipleCandidates()) + if (auto *FTD = FD->getPrimaryTemplate()) + TPL = FTD->getTemplateParameters(); + } else if (auto *VTSD = + dyn_cast(Node->getMemberDecl())) + TPL = VTSD->getSpecializedTemplate()->getTemplateParameters(); if (Node->hasExplicitTemplateArgs()) - printTemplateArgumentList(OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy, TPL); } void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { @@ -1881,8 +1835,12 @@ assert(Args); if (Args->size() != 1) { + const TemplateParameterList *TPL = nullptr; + if (!DRE->hadMultipleCandidates()) + if (const auto *TD = dyn_cast(DRE->getDecl())) + TPL = TD->getTemplateParameters(); OS << "operator\"\"" << Node->getUDSuffix()->getName(); - printTemplateArgumentList(OS, Args->asArray(), Policy); + printTemplateArgumentList(OS, Args->asArray(), Policy, TPL); OS << "()"; return; } @@ -2332,7 +2290,8 @@ OS << "template "; OS << E->getFoundDecl()->getName(); printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(), - Policy); + Policy, + E->getNamedConcept()->getTemplateParameters()); } void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) { diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -50,8 +50,11 @@ /// \param Out the raw_ostream instance to use for printing. /// /// \param Policy the printing policy for EnumConstantDecl printing. -static void printIntegral(const TemplateArgument &TemplArg, - raw_ostream &Out, const PrintingPolicy& Policy) { +/// +/// \param IncludeType If set, ensure that the type of the expression printed +/// matches the type of the template argument. +static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, + const PrintingPolicy &Policy, bool IncludeType) { const Type *T = TemplArg.getIntegralType().getTypePtr(); const llvm::APSInt &Val = TemplArg.getAsIntegral(); @@ -68,16 +71,66 @@ } } - if (T->isBooleanType() && !Policy.MSVCFormatting) { - Out << (Val.getBoolValue() ? "true" : "false"); + if (Policy.MSVCFormatting) + IncludeType = false; + + if (T->isBooleanType()) { + if (!Policy.MSVCFormatting) + Out << (Val.getBoolValue() ? "true" : "false"); + else + Out << Val; } else if (T->isCharType()) { - const char Ch = Val.getZExtValue(); - Out << ((Ch == '\'') ? "'\\" : "'"); - Out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true); - Out << "'"; - } else { + if (IncludeType) { + if (T->isSpecificBuiltinType(BuiltinType::SChar)) + Out << "(signed char)"; + else if (T->isSpecificBuiltinType(BuiltinType::UChar)) + Out << "(unsigned char)"; + } + CharacterLiteral::print(Val.getZExtValue(), CharacterLiteral::Ascii, Out); + } else if (T->isAnyCharacterType() && !Policy.MSVCFormatting) { + CharacterLiteral::CharacterKind Kind; + if (T->isWideCharType()) + Kind = CharacterLiteral::Wide; + else if (T->isChar8Type()) + Kind = CharacterLiteral::UTF8; + else if (T->isChar16Type()) + Kind = CharacterLiteral::UTF16; + else if (T->isChar32Type()) + Kind = CharacterLiteral::UTF32; + else + Kind = CharacterLiteral::Ascii; + CharacterLiteral::print(Val.getExtValue(), Kind, Out); + } else if (IncludeType) { + if (const auto *BT = T->getAs()) { + switch (BT->getKind()) { + case BuiltinType::ULongLong: + Out << Val << "ULL"; + break; + case BuiltinType::LongLong: + Out << Val << "LL"; + break; + case BuiltinType::ULong: + Out << Val << "UL"; + break; + case BuiltinType::Long: + Out << Val << "L"; + break; + case BuiltinType::UInt: + Out << Val << "U"; + break; + case BuiltinType::Int: + Out << Val; + break; + default: + Out << "(" << T->getCanonicalTypeInternal().getAsString(Policy) << ")" + << Val; + break; + } + } else + Out << "(" << T->getCanonicalTypeInternal().getAsString(Policy) << ")" + << Val; + } else Out << Val; - } } static unsigned getArrayDepth(QualType type) { @@ -360,8 +413,9 @@ llvm_unreachable("Invalid TemplateArgument Kind!"); } -void TemplateArgument::print(const PrintingPolicy &Policy, - raw_ostream &Out) const { +void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, + bool IncludeType) const { + switch (getKind()) { case Null: Out << "(no value)"; @@ -375,10 +429,10 @@ } case Declaration: { + // FIXME: Include the type if it's not obvious from the context. NamedDecl *ND = getAsDecl(); if (getParamTypeForDecl()->isRecordType()) { if (auto *TPO = dyn_cast(ND)) { - // FIXME: Include the type if it's not obvious from the context. TPO->printAsInit(Out); break; } @@ -392,6 +446,7 @@ } case NullPtr: + // FIXME: Include the type if it's not obvious from the context. Out << "nullptr"; break; @@ -405,7 +460,7 @@ break; case Integral: - printIntegral(*this, Out, Policy); + printIntegral(*this, Out, Policy, IncludeType); break; case Expression: @@ -421,7 +476,7 @@ else Out << ", "; - P.print(Policy, Out); + P.print(Policy, Out, IncludeType); } Out << ">"; break; @@ -432,7 +487,7 @@ LangOptions LO; // FIXME! see also TemplateName::dump(). LO.CPlusPlus = true; LO.Bool = true; - print(PrintingPolicy(LO), Out); + print(PrintingPolicy(LO), Out, /*IncludeType*/ true); } LLVM_DUMP_METHOD void TemplateArgument::dump() const { dump(llvm::errs()); } @@ -527,7 +582,7 @@ LangOptions LangOpts; LangOpts.CPlusPlus = true; PrintingPolicy Policy(LangOpts); - Arg.print(Policy, OS); + Arg.print(Policy, OS, /*IncludeType*/ true); return DB << OS.str(); } } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1843,16 +1843,17 @@ } static void printArgument(const TemplateArgument &A, const PrintingPolicy &PP, - llvm::raw_ostream &OS) { - A.print(PP, OS); + llvm::raw_ostream &OS, bool IncludeType) { + A.print(PP, OS, IncludeType); } static void printArgument(const TemplateArgumentLoc &A, - const PrintingPolicy &PP, llvm::raw_ostream &OS) { + const PrintingPolicy &PP, llvm::raw_ostream &OS, + bool IncludeType) { const TemplateArgument::ArgKind &Kind = A.getArgument().getKind(); if (Kind == TemplateArgument::ArgKind::Type) return A.getTypeSourceInfo()->getType().print(OS, PP); - return A.getArgument().print(PP, OS); + return A.getArgument().print(PP, OS, IncludeType); } static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg, @@ -1989,13 +1990,14 @@ return false; } -template +template static void printTo(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, bool SkipBrackets, - const TemplateParameterList *TPL) { + const TemplateParameterList *TPL, bool IsPack, + unsigned ParmIndex) { // Drop trailing template arguments that match default arguments. if (TPL && Policy.SuppressDefaultTemplateArgs && - !Policy.PrintCanonicalTypes && !Args.empty() && + !Policy.PrintCanonicalTypes && !Args.empty() && !IsPack && Args.size() <= TPL->size()) { ASTContext &Ctx = TPL->getParam(0)->getASTContext(); llvm::SmallVector OrigArgs; @@ -2022,12 +2024,15 @@ if (Argument.getKind() == TemplateArgument::Pack) { if (Argument.pack_size() && !FirstArg) OS << Comma; - printTo(ArgOS, Argument.getPackAsArray(), Policy, true, nullptr); + printTo(ArgOS, Argument.getPackAsArray(), Policy, true, TPL, + /*IsPack*/ true, ParmIndex); } else { if (!FirstArg) OS << Comma; // Tries to print the argument with location info if exists. - printArgument(Arg, Policy, ArgOS); + printArgument( + Arg, Policy, ArgOS, + TemplateParameterList::shouldIncludeTypeForArgument(TPL, ParmIndex)); } StringRef ArgString = ArgOS.str(); @@ -2044,6 +2049,10 @@ NeedSpace = Policy.SplitTemplateClosers && !ArgString.empty() && ArgString.back() == '>'; FirstArg = false; + + // Use same template parameter for all elements of Pack + if (!IsPack) + ParmIndex++; } if (NeedSpace) @@ -2064,14 +2073,14 @@ ArrayRef Args, const PrintingPolicy &Policy, const TemplateParameterList *TPL) { - printTo(OS, Args, Policy, false, TPL); + printTo(OS, Args, Policy, false, TPL, /*isPack*/ false, /*parmIndex*/ 0); } void clang::printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, const TemplateParameterList *TPL) { - printTo(OS, Args, Policy, false, TPL); + printTo(OS, Args, Policy, false, TPL, /*isPack*/ false, /*parmIndex*/ 0); } std::string Qualifiers::getAsString() const { diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp --- a/clang/lib/Analysis/PathDiagnostic.cpp +++ b/clang/lib/Analysis/PathDiagnostic.cpp @@ -898,7 +898,7 @@ if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { describeTemplateParameters(Out, TArg.getPackAsArray(), LO); } else { - TArg.print(PrintingPolicy(LO), Out); + TArg.print(PrintingPolicy(LO), Out, /*IncludeType*/ true); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -976,15 +976,20 @@ } static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, - TemplateArgumentListInfo &Args) { + TemplateArgumentListInfo &Args, + const TemplateParameterList *Params) { SmallString<128> SS; llvm::raw_svector_ostream OS(SS); bool First = true; + unsigned I = 0; for (auto &Arg : Args.arguments()) { if (!First) OS << ", "; - Arg.getArgument().print(PrintingPolicy, OS); + Arg.getArgument().print( + PrintingPolicy, OS, + TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); First = false; + I++; } return std::string(OS.str()); } @@ -996,7 +1001,7 @@ auto DiagnoseMissing = [&] { if (DiagID) S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.getPrintingPolicy(), - Args); + Args, /*Params*/ nullptr); return true; }; @@ -1034,7 +1039,8 @@ if (DiagID) S.RequireCompleteType( Loc, TraitTy, DiagID, - printTemplateArgs(S.Context.getPrintingPolicy(), Args)); + printTemplateArgs(S.Context.getPrintingPolicy(), Args, + TraitTD->getTemplateParameters())); return true; } @@ -1089,7 +1095,8 @@ Sema::SemaDiagnosticBuilder diagnoseNotICE(Sema &S, SourceLocation Loc) override { return S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) - << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + << printTemplateArgs(S.Context.getPrintingPolicy(), Args, + /*Params*/ nullptr); } } Diagnoser(R, Args); @@ -1125,7 +1132,8 @@ if (!TD) { R.suppressDiagnostics(); S.Diag(Loc, diag::err_decomp_decl_std_tuple_element_not_specialized) - << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + << printTemplateArgs(S.Context.getPrintingPolicy(), Args, + /*Params*/ nullptr); if (!R.empty()) S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at); return QualType(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3570,7 +3570,9 @@ OS << VD->getName(); if (const auto *IV = dyn_cast(VD)) { // This is a template variable, print the expanded template arguments. - printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy); + printTemplateArgumentList( + OS, IV->getTemplateArgs().asArray(), Policy, + IV->getSpecializedTemplate()->getTemplateParameters()); } return true; } @@ -10908,7 +10910,9 @@ } Out << " = "; - Args[I].print(getPrintingPolicy(), Out); + Args[I].print( + getPrintingPolicy(), Out, + TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); } Out << ']'; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4705,10 +4705,9 @@ llvm::raw_string_ostream OS(Buf); OS << "'" << Concept->getName(); if (TypeLoc.hasExplicitTemplateArgs()) { - OS << "<"; - for (const auto &Arg : Type.getTypeConstraintArguments()) - Arg.print(S.getPrintingPolicy(), OS); - OS << ">"; + printTemplateArgumentList( + OS, Type.getTypeConstraintArguments(), S.getPrintingPolicy(), + Type.getTypeConstraintConcept()->getTemplateParameters()); } OS << "'"; OS.flush(); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -805,9 +805,10 @@ SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); cast(Active->Entity)->printName(OS); - if (!isa(Active->Entity)) + if (!isa(Active->Entity)) { printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); + } Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() << Active->InstantiationRange; break; diff --git a/clang/test/Analysis/eval-predefined-exprs.cpp b/clang/test/Analysis/eval-predefined-exprs.cpp --- a/clang/test/Analysis/eval-predefined-exprs.cpp +++ b/clang/test/Analysis/eval-predefined-exprs.cpp @@ -14,7 +14,7 @@ clang_analyzer_dump(__PRETTY_FUNCTION__); // expected-warning@-3 {{&Element{"func",0 S64b,char}}} // expected-warning@-3 {{&Element{"func",0 S64b,char}}} - // expected-warning@-3 {{&Element{"void func(U) [T = Class, Value = 42, U = char]",0 S64b,char}}} + // expected-warning@-3 {{&Element{"void func(U) [T = Class, Value = 42ULL, U = char]",0 S64b,char}}} #ifdef ANALYZER_MS clang_analyzer_dump(__FUNCDNAME__); @@ -23,8 +23,8 @@ clang_analyzer_dump(L__FUNCSIG__); // expected-warning@-4 {{&Element{"??$func@UClass@?1??foo@@YAXXZ@$0CK@D@@YAXD@Z",0 S64b,char}}} // expected-warning@-4 {{&Element{L"func",0 S64b,wchar_t}}} - // expected-warning@-4 {{&Element{"void __cdecl func(U) [T = Class, Value = 42, U = char]",0 S64b,char}}} - // expected-warning@-4 {{&Element{L"void __cdecl func(U) [T = Class, Value = 42, U = char]",0 S64b,wchar_t}}} + // expected-warning@-4 {{&Element{"void __cdecl func(U) [T = Class, Value = 42ULL, U = char]",0 S64b,char}}} + // expected-warning@-4 {{&Element{L"void __cdecl func(U) [T = Class, Value = 42ULL, U = char]",0 S64b,wchar_t}}} #endif } diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p12.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p12.cpp --- a/clang/test/CXX/lex/lex.literal/lex.ext/p12.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p12.cpp @@ -8,7 +8,8 @@ template<> struct check{}; template int operator""_x() { // #1 expected-warning {{string literal operator templates are a GNU extension}} - check chars; // expected-error {{implicit instantiation of undefined template 'check'}} expected-error {{implicit instantiation of undefined template 'check'}} + check chars; // expected-error {{implicit instantiation of undefined template 'check'}} \ + // expected-error {{implicit instantiation of undefined template 'check'}} return 1; } void *operator""_x(const char*); // #2 @@ -18,4 +19,4 @@ int d = "test"_x; // expected-note {{in instantiation of function template specialization 'operator""_x' requested here}} int e = uR"("ั‚ะตัั‚ ๐€€)"_x; int f = UR"("ั‚ะตัั‚ ๐€€)"_x; -int g = UR"("ั‚ะตัั‚_๐€€)"_x; // expected-note {{in instantiation of function template specialization 'operator""_x' requested here}} +int g = UR"("ั‚ะตัั‚_๐€€)"_x; // expected-note {{in instantiation of function template specialization 'operator""_x' requested here}} diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p13.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p13.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p13.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +template struct check; // expected-note {{template is declared here}} +template <> +struct check {}; +template int operator""_x() { // #1 expected-warning {{string literal operator templates are a GNU extension}} + check chars; // expected-error {{implicit instantiation of undefined template 'check'}} + return 1; +} +int a = u8"\"ั‚ะตัั‚ ๐€€"_x; +int b = u8"\"ั‚ะตัั‚_๐€€"_x; // expected-note {{in instantiation of function template specialization 'operator""_x' requested here}} + +template struct C{}; +C::D d; // expected-error {{no type named 'D' in 'C'}} diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p14.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p14.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p14.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++2a -verify -triple x86_64-unknown-linux %s + +template struct check; // expected-note {{template is declared here}} +template <> +struct check {}; +template int operator""_x() { // #1 expected-warning {{string literal operator templates are a GNU extension}} + check chars; // expected-error {{implicit instantiation of undefined template 'check'}} + return 1; +} +void *operator""_x(const char *); // #2 +int h = LR"("ั‚ะตัั‚_๐€€)"_x; // expected-note {{in instantiation of function template specialization 'operator""_x' requested here}} diff --git a/clang/test/CodeGenCXX/debug-info-codeview-template-literal.cpp b/clang/test/CodeGenCXX/debug-info-codeview-template-literal.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-codeview-template-literal.cpp @@ -0,0 +1,9 @@ +// RUN: %clang -g -std=c++2a -target x86_64-windows-msvc -Wno-gnu-string-literal-operator-template %s -S -emit-llvm -o - | FileCheck %s + +template struct check; +template int operator""_x() { + return 1; +} + +int b = u8"\"ั‚ะตัั‚_๐€€"_x; +// CHECK: _x diff --git a/clang/test/CodeGenCXX/debug-info-codeview-template-type.cpp b/clang/test/CodeGenCXX/debug-info-codeview-template-type.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-codeview-template-type.cpp @@ -0,0 +1,12 @@ +// RUN: %clang -std=c++11 -g -target x86_64-windows-msvc -S -emit-llvm -o - %s | FileCheck %s + +template +void foo() { +} + +void instantiate_foo() { + foo<10>(); + // CHECK: foo<10> + foo(); + // CHECK: foo<1> +} diff --git a/clang/test/SemaCXX/builtin-align-cxx.cpp b/clang/test/SemaCXX/builtin-align-cxx.cpp --- a/clang/test/SemaCXX/builtin-align-cxx.cpp +++ b/clang/test/SemaCXX/builtin-align-cxx.cpp @@ -31,10 +31,10 @@ void test() { test_templated_arguments(); // fine test_templated_arguments(); - // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments'}} + // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments'}} // expected-note@-2{{forward declaration of 'fwddecl'}} test_templated_arguments(); // invalid alignment value - // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments'}} + // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments'}} } template diff --git a/clang/test/SemaCXX/cxx11-ast-print.cpp b/clang/test/SemaCXX/cxx11-ast-print.cpp --- a/clang/test/SemaCXX/cxx11-ast-print.cpp +++ b/clang/test/SemaCXX/cxx11-ast-print.cpp @@ -40,7 +40,7 @@ const char *p10 = 3.300e+15_fritz; template const char *operator"" _suffix(); -// CHECK: const char *PR23120 = operator""_suffix(); +// CHECK: const char *PR23120 = operator""_suffix(); const char *PR23120 = U"๐ท"_suffix; // PR28885 diff --git a/clang/test/SemaCXX/cxx1z-ast-print.cpp b/clang/test/SemaCXX/cxx1z-ast-print.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/cxx1z-ast-print.cpp @@ -0,0 +1,11 @@ +//RUN: %clang_cc1 -std=c++1z -verify -ast-print %s | FileCheck %s + +struct TypeSuffix { + template static int x; // expected-note {{forward declaration of template entity is here}} + template static int y; // expected-note {{forward declaration of template entity is here}} +}; +// CHECK: int k = TypeSuffix().x + TypeSuffix().y; +int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>; // expected-warning {{instantiation of variable 'TypeSuffix::x<0>' required here, but no definition is available}} \ + // expected-note {{add an explicit instantiation declaration to suppress this warning if 'TypeSuffix::x<0>' is explicitly instantiated in another translation unit}} \ + // expected-warning {{instantiation of variable 'TypeSuffix::y<0L>' required here, but no definition is available}} \ + // expected-note {{add an explicit instantiation declaration to suppress this warning if 'TypeSuffix::y<0L>' is explicitly instantiated in another translation unit}} diff --git a/clang/test/SemaCXX/matrix-type-builtins.cpp b/clang/test/SemaCXX/matrix-type-builtins.cpp --- a/clang/test/SemaCXX/matrix-type-builtins.cpp +++ b/clang/test/SemaCXX/matrix-type-builtins.cpp @@ -30,14 +30,14 @@ MyMatrix Mat2; Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1); Mat1.value = transpose(Mat1); - // expected-note@-1 {{in instantiation of function template specialization 'transpose' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'transpose' requested here}} Mat1.value = transpose(Mat2); - // expected-note@-1 {{in instantiation of function template specialization 'transpose' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'transpose' requested here}} MyMatrix Mat3; Mat3.value = transpose(Mat2); - // expected-note@-1 {{in instantiation of function template specialization 'transpose' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'transpose' requested here}} } template @@ -55,13 +55,13 @@ void test_column_major_loads_template(unsigned *Ptr1, float *Ptr2) { MyMatrix Mat1; Mat1.value = column_major_load(Mat1, Ptr1); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_load' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_load' requested here}} column_major_load(Mat1, Ptr1); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_load' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_load' requested here}} MyMatrix Mat2; Mat1.value = column_major_load(Mat2, Ptr2); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_load' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_load' requested here}} } constexpr int constexpr1() { return 1; } @@ -116,10 +116,10 @@ void test_column_major_stores_template(MyMatrix &M1, unsigned *Ptr1, MyMatrix &M2, float *Ptr2) { column_major_store(M1, Ptr2, 10); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_store' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_store' requested here}} column_major_store(M2, Ptr2); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_store &, float *, 1>' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_store &, float *, 1U>' requested here}} } template @@ -139,13 +139,13 @@ void test_column_major_store_template(unsigned *Ptr1, float *Ptr2) { MyMatrix Mat1; column_major_store(Mat1, Ptr1); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_store'}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_store'}} column_major_store(Mat1, Ptr2); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_store'}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_store'}} MyMatrix Mat2; column_major_store(Mat2, Ptr1); - // expected-note@-1 {{in instantiation of function template specialization 'column_major_store'}} + // expected-note@-1 {{in instantiation of function template specialization 'column_major_store'}} } void test_column_major_store_constexpr(unsigned *Ptr, MyMatrix &M) { diff --git a/clang/test/SemaCXX/matrix-type-operators.cpp b/clang/test/SemaCXX/matrix-type-operators.cpp --- a/clang/test/SemaCXX/matrix-type-operators.cpp +++ b/clang/test/SemaCXX/matrix-type-operators.cpp @@ -28,13 +28,13 @@ Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1); unsigned v1 = add(Mat1, Mat1); // expected-error@-1 {{cannot initialize a variable of type 'unsigned int' with an rvalue of type 'typename MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}} - // expected-note@-2 {{in instantiation of function template specialization 'add' requested here}} + // expected-note@-2 {{in instantiation of function template specialization 'add' requested here}} Mat1.value = add(Mat1, Mat2); - // expected-note@-1 {{in instantiation of function template specialization 'add' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'add' requested here}} Mat1.value = add(Mat2, Mat3); - // expected-note@-1 {{in instantiation of function template specialization 'add' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'add' requested here}} } template @@ -56,13 +56,13 @@ Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1); unsigned v1 = subtract(Mat1, Mat1); // expected-error@-1 {{cannot initialize a variable of type 'unsigned int' with an rvalue of type 'typename MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}} - // expected-note@-2 {{in instantiation of function template specialization 'subtract' requested here}} + // expected-note@-2 {{in instantiation of function template specialization 'subtract' requested here}} Mat1.value = subtract(Mat1, Mat2); - // expected-note@-1 {{in instantiation of function template specialization 'subtract' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'subtract' requested here}} Mat1.value = subtract(Mat2, Mat3); - // expected-note@-1 {{in instantiation of function template specialization 'subtract' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'subtract' requested here}} } template @@ -89,15 +89,15 @@ MyMatrix Mat3; Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1); unsigned v1 = multiply(Mat1, Mat1); - // expected-note@-1 {{in instantiation of function template specialization 'multiply' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'multiply' requested here}} // expected-error@-2 {{cannot initialize a variable of type 'unsigned int' with an rvalue of type 'typename MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}} MyMatrix Mat4; Mat1.value = multiply(Mat4, Mat2); - // expected-note@-1 {{in instantiation of function template specialization 'multiply' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'multiply' requested here}} Mat1.value = multiply(Mat3, Mat1); - // expected-note@-1 {{in instantiation of function template specialization 'multiply' requested here}} + // expected-note@-1 {{in instantiation of function template specialization 'multiply' requested here}} Mat4.value = Mat4.value * Mat1; // expected-error@-1 {{no viable conversion from 'MyMatrix' to 'unsigned int'}} diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp --- a/clang/test/SemaTemplate/address_space-dependent.cpp +++ b/clang/test/SemaTemplate/address_space-dependent.cpp @@ -102,7 +102,7 @@ HasASTemplateFields<1> HASTF; neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}} correct<0x7FFFED>(); - tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650>' requested here}} + tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}} __attribute__((address_space(1))) char *x; __attribute__((address_space(2))) char *y; diff --git a/clang/test/SemaTemplate/default-arguments-ast-print.cpp b/clang/test/SemaTemplate/default-arguments-ast-print.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaTemplate/default-arguments-ast-print.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -ast-print %s | FileCheck %s + +template class Foo; + +template <> class Foo { int method1(); }; + +using int_type = int; + +int Foo::method1() { + // CHECK: int Foo::method1() + return 10; +} diff --git a/clang/test/SemaTemplate/delegating-constructors.cpp b/clang/test/SemaTemplate/delegating-constructors.cpp --- a/clang/test/SemaTemplate/delegating-constructors.cpp +++ b/clang/test/SemaTemplate/delegating-constructors.cpp @@ -9,7 +9,7 @@ public: template string(const char (&str)[N]) - : string(str) {} // expected-error{{constructor for 'string<6>' creates a delegation cycle}} + : string(str) {} // expected-error{{constructor for 'string<6U>' creates a delegation cycle}} }; void f() { diff --git a/clang/test/SemaTemplate/matrix-type.cpp b/clang/test/SemaTemplate/matrix-type.cpp --- a/clang/test/SemaTemplate/matrix-type.cpp +++ b/clang/test/SemaTemplate/matrix-type.cpp @@ -17,7 +17,7 @@ void instantiate_template_3() { matrix_template_3<1, 10>(); - matrix_template_3<0, 10>(); // expected-note{{in instantiation of function template specialization 'matrix_template_3<0, 10>' requested here}} + matrix_template_3<0, 10>(); // expected-note{{in instantiation of function template specialization 'matrix_template_3<0U, 10U>' requested here}} } template @@ -27,7 +27,7 @@ void instantiate_template_4() { matrix_template_4<2, 10>(); - matrix_template_4<-3, 10>(); // expected-note{{in instantiation of function template specialization 'matrix_template_4<-3, 10>' requested here}} + matrix_template_4<-3, 10>(); // expected-note{{in instantiation of function template specialization 'matrix_template_4<-3, 10U>' requested here}} } template diff --git a/clang/test/SemaTemplate/temp_arg_enum_printing.cpp b/clang/test/SemaTemplate/temp_arg_enum_printing.cpp --- a/clang/test/SemaTemplate/temp_arg_enum_printing.cpp +++ b/clang/test/SemaTemplate/temp_arg_enum_printing.cpp @@ -17,7 +17,7 @@ NamedEnumNS::foo(); // CHECK: template<> void foo() NamedEnumNS::foo<(NamedEnum)1>(); - // CHECK: template<> void foo<2>() + // CHECK: template<> void foo<(NamedEnumNS::NamedEnum)2>() NamedEnumNS::foo<(NamedEnum)2>(); } diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -270,6 +270,23 @@ void test_char_possibly_negative() { enable_if_char<'\x02'>::type i; } // expected-error{{enable_if_char<'\x02'>'; did you mean 'enable_if_char<'a'>::type'?}} void test_char_single_quote() { enable_if_char<'\''>::type i; } // expected-error{{enable_if_char<'\''>'; did you mean 'enable_if_char<'a'>::type'?}} void test_char_backslash() { enable_if_char<'\\'>::type i; } // expected-error{{enable_if_char<'\\'>'; did you mean 'enable_if_char<'a'>::type'?}} + + template struct enable_if_int {}; + template <> struct enable_if_int<1> { typedef int type; }; // expected-note{{'enable_if_int<1>::type' declared here}} + void test_int() { enable_if_int<2>::type i; } // expected-error{{enable_if_int<2>'; did you mean 'enable_if_int<1>::type'?}} + + template struct enable_if_unsigned_int {}; + template <> struct enable_if_unsigned_int<1> { typedef int type; }; // expected-note{{'enable_if_unsigned_int<1>::type' declared here}} + void test_unsigned_int() { enable_if_unsigned_int<2>::type i; } // expected-error{{enable_if_unsigned_int<2>'; did you mean 'enable_if_unsigned_int<1>::type'?}} + + template struct enable_if_unsigned_long_long {}; + template <> struct enable_if_unsigned_long_long<1> { typedef int type; }; // expected-note{{'enable_if_unsigned_long_long<1>::type' declared here}} + void test_unsigned_long_long() { enable_if_unsigned_long_long<2>::type i; } // expected-error{{enable_if_unsigned_long_long<2>'; did you mean 'enable_if_unsigned_long_long<1>::type'?}} + + template struct enable_if_long_long {}; + template <> struct enable_if_long_long<1> { typedef int type; }; // expected-note{{'enable_if_long_long<1>::type' declared here}} + void test_long_long() { enable_if_long_long<2>::type i; } // expected-error{{enable_if_long_long<2>'; did you mean 'enable_if_long_long<1>::type'?}} + } namespace PR10579 { diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -528,3 +528,33 @@ x1.f(x2); } } + +namespace TypeSuffix { + template struct A {}; + template <> struct A<1> { using type = int; }; // expected-note {{'A<1>::type' declared here}} + A<1L>::type a; // expected-error {{no type named 'type' in 'TypeSuffix::A<1L>'; did you mean 'A<1>::type'?}} + + template struct B {}; + template <> struct B<1> { using type = int; }; // expected-note {{'B<1>::type' declared here}} + B<2>::type b; // expected-error {{no type named 'type' in 'TypeSuffix::B<2>'; did you mean 'B<1>::type'?}} + + template struct C {}; + template <> struct C<'a'> { using type = signed char; }; // expected-note {{'C<'a'>::type' declared here}} + C<(signed char)'a'>::type c; // expected-error {{no type named 'type' in 'TypeSuffix::C<(signed char)'a'>'; did you mean 'C<'a'>::type'?}} + + template struct D {}; + template <> struct D<'a'> { using type = signed char; }; // expected-note {{'D<'a'>::type' declared here}} + D<'b'>::type d; // expected-error {{no type named 'type' in 'TypeSuffix::D<'b'>'; did you mean 'D<'a'>::type'?}} + + template struct E {}; + template <> struct E<'a'> { using type = unsigned char; }; // expected-note {{'E<'a'>::type' declared here}} + E<(unsigned char)'a'>::type e; // expected-error {{no type named 'type' in 'TypeSuffix::E<(unsigned char)'a'>'; did you mean 'E<'a'>::type'?}} + + template struct F {}; + template <> struct F<'a'> { using type = unsigned char; }; // expected-note {{'F<'a'>::type' declared here}} + F<'b'>::type f; // expected-error {{no type named 'type' in 'TypeSuffix::F<'b'>'; did you mean 'F<'a'>::type'?}} + + template struct X {}; + X<1, 1u>::type y; // expected-error {{no type named 'type' in 'TypeSuffix::X<1, 1U>'}} + X<1, 1>::type z; // expected-error {{no type named 'type' in 'TypeSuffix::X<1, 1>'}} +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5185,8 +5185,9 @@ SmallString<128> Str; llvm::raw_svector_ostream OS(Str); OS << *ClassSpec; - printTemplateArgumentList(OS, ClassSpec->getTemplateArgs().asArray(), - Policy); + printTemplateArgumentList( + OS, ClassSpec->getTemplateArgs().asArray(), Policy, + ClassSpec->getSpecializedTemplate()->getTemplateParameters()); return cxstring::createDup(OS.str()); } diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp --- a/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp @@ -20,7 +20,7 @@ llvm::raw_string_ostream Stream(ArgStr); const TemplateArgument &Arg = ArgLoc.getArgument(); - Arg.print(Context->getPrintingPolicy(), Stream); + Arg.print(Context->getPrintingPolicy(), Stream, /*IncludeType*/ true); Match(Stream.str(), ArgLoc.getLocation()); return ExpectedLocationVisitor:: TraverseTemplateArgumentLoc(ArgLoc);