<div style="font-family: arial, helvetica, sans-serif"><font size="2">I know we chatted about this already, but wanted to mention:<div><br></div><div>1) Release notes</div><div>2) Documentation updates</div><div><br></div>
<div><br></div><div>Thanks again, I'm really excited to have this. :: goes and builds a new Clang ::</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Jun 26, 2012 at 11:18 AM, Richard Trieu <span dir="ltr"><<a href="mailto:rtrieu@google.com" target="_blank">rtrieu@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rtrieu<br>
Date: Tue Jun 26 13:18:47 2012<br>
New Revision: 159216<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=159216&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=159216&view=rev</a><br>
Log:<br>
Add template type diffing to Clang. This feature will provide a better<br>
comparison between two templated types when they both appear in a diagnostic.<br>
Type elision will remove indentical template arguments, which can be disabled<br>
with -fno-elide-type. Cyan highlighting is applied to the differing types.<br>
<br>
For more formatting, -fdiagnostic-show-template-tree will output the template<br>
type as an indented text tree, with differences appearing inline. Template<br>
tree works with or without type elision.<br>
<br>
Added:<br>
cfe/trunk/test/Misc/diag-template-diffing.cpp<br>
Modified:<br>
cfe/trunk/include/clang/Basic/Diagnostic.h<br>
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
cfe/trunk/include/clang/Driver/Options.td<br>
cfe/trunk/include/clang/Frontend/DiagnosticOptions.h<br>
cfe/trunk/lib/AST/ASTDiagnostic.cpp<br>
cfe/trunk/lib/Basic/Diagnostic.cpp<br>
cfe/trunk/lib/Driver/Tools.cpp<br>
cfe/trunk/lib/Frontend/CompilerInvocation.cpp<br>
cfe/trunk/lib/Frontend/TextDiagnostic.cpp<br>
cfe/trunk/lib/Frontend/Warnings.cpp<br>
cfe/trunk/test/Misc/diag-aka-types.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/Diagnostic.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)<br>
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Tue Jun 26 13:18:47 2012<br>
@@ -153,7 +153,8 @@<br>
ak_declarationname, // DeclarationName<br>
ak_nameddecl, // NamedDecl *<br>
ak_nestednamespec, // NestedNameSpecifier *<br>
- ak_declcontext // DeclContext *<br>
+ ak_declcontext, // DeclContext *<br>
+ ak_qualtype_pair // pair<QualType, QualType><br>
};<br>
<br>
/// Specifies which overload candidates to display when overload resolution<br>
@@ -175,6 +176,9 @@<br>
bool ErrorsAsFatal; // Treat errors like fatal errors.<br>
bool SuppressSystemWarnings; // Suppress warnings in system headers.<br>
bool SuppressAllDiagnostics; // Suppress all diagnostics.<br>
+ bool ElideType; // Elide common types of templates.<br>
+ bool PrintTemplateTree; // Print a tree when comparing templates.<br>
+ bool ShowColors; // Color printing is enabled.<br>
OverloadsShown ShowOverloads; // Which overload candidates to show.<br>
unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit.<br>
unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack,<br>
@@ -438,7 +442,22 @@<br>
SuppressAllDiagnostics = Val;<br>
}<br>
bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }<br>
-<br>
+<br>
+ /// \brief Set type eliding, to skip outputting same types occurring in<br>
+ /// template types.<br>
+ void setElideType(bool Val = true) { ElideType = Val; }<br>
+ bool getElideType() { return ElideType; }<br>
+<br>
+ /// \brief Set tree printing, to outputting the template difference in a<br>
+ /// tree format.<br>
+ void setPrintTemplateTree(bool Val = false) { PrintTemplateTree = Val; }<br>
+ bool getPrintTemplateTree() { return PrintTemplateTree; }<br>
+<br>
+ /// \brief Set color printing, so the type diffing will inject color markers<br>
+ /// into the output.<br>
+ void setShowColors(bool Val = false) { ShowColors = Val; }<br>
+ bool getShowColors() { return ShowColors; }<br>
+<br>
/// \brief Specify which overload candidates to show when overload resolution<br>
/// fails. By default, we show all candidates.<br>
void setShowOverloads(OverloadsShown Val) {<br>
@@ -1058,7 +1077,6 @@<br>
return DiagObj->DiagArgumentsVal[Idx];<br>
}<br>
<br>
-<br>
/// getNumRanges - Return the number of source ranges associated with this<br>
/// diagnostic.<br>
unsigned getNumRanges() const {<br>
@@ -1223,6 +1241,20 @@<br>
}<br>
};<br>
<br>
+// Struct used for sending info about how a type should be printed.<br>
+struct TemplateDiffTypes {<br>
+ intptr_t FromType;<br>
+ intptr_t ToType;<br>
+ unsigned PrintTree : 1;<br>
+ unsigned PrintFromType : 1;<br>
+ unsigned ElideType : 1;<br>
+ unsigned ShowColors : 1;<br>
+};<br>
+<br>
+/// Special character that the diagnostic printer will use to toggle the bold<br>
+/// attribute. The character itself will be not be printed.<br>
+const char ToggleHighlight = 127;<br>
+<br>
} // end namespace clang<br>
<br>
#endif<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jun 26 13:18:47 2012<br>
@@ -2162,7 +2162,7 @@<br>
"function (the implicit copy assignment operator)|"<br>
"function (the implicit move assignment operator)|"<br>
"constructor (inherited)}0%1"<br>
- " not viable: no known conversion from %2 to %3 for "<br>
+ " not viable: no known conversion %diff{from | to | }2,3for "<br>
"%select{%ordinal5 argument|object argument}4; "<br>
"%select{|dereference the argument with *|"<br>
"take the address of the argument with &|"<br>
<br>
Modified: cfe/trunk/include/clang/Driver/Options.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Driver/Options.td (original)<br>
+++ cfe/trunk/include/clang/Driver/Options.td Tue Jun 26 13:18:47 2012<br>
@@ -358,6 +358,9 @@<br>
Group<f_Group>, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">;<br>
def fdiagnostics_format_EQ : Joined<"-fdiagnostics-format=">, Group<f_clang_Group>;<br>
def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>;<br>
+def fdiagnostics_show_template_tree : Flag<"-fdiagnostics-show-template-tree">,<br>
+ Group<f_Group>, Flags<[CC1Option]>,<br>
+ HelpText<"Print a template comparison tree for differing templates">;<br>
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>,<br>
HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>;<br>
def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>;<br>
@@ -365,6 +368,9 @@<br>
def fdwarf_directory_asm : Flag<"-fdwarf-directory-asm">, Group<f_Group>;<br>
def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">, Group<f_Group>, Flags<[CC1Option]>;<br>
def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>;<br>
+def fno_elide_type : Flag<"-fno-elide-type">, Group<f_Group>,<br>
+ Flags<[CC1Option]>,<br>
+ HelpText<"Do not elide types when printing diagnostics">;<br>
def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>;<br>
def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,<br>
HelpText<"Emit all declarations, even if unused">;<br>
<br>
Modified: cfe/trunk/include/clang/Frontend/DiagnosticOptions.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/DiagnosticOptions.h?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/DiagnosticOptions.h?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Frontend/DiagnosticOptions.h (original)<br>
+++ cfe/trunk/include/clang/Frontend/DiagnosticOptions.h Tue Jun 26 13:18:47 2012<br>
@@ -47,6 +47,9 @@<br>
/// diagnostics, indicated by markers in the<br>
/// input source file.<br>
<br>
+ unsigned ElideType: 1; /// Elide identical types in template diffing<br>
+ unsigned ShowTemplateTree: 1; /// Print a template tree when diffing<br>
+<br>
unsigned ErrorLimit; /// Limit # errors emitted.<br>
unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace.<br>
unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.<br>
<br>
Modified: cfe/trunk/lib/AST/ASTDiagnostic.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTDiagnostic.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTDiagnostic.cpp Tue Jun 26 13:18:47 2012<br>
@@ -14,7 +14,11 @@<br>
<br>
#include "clang/AST/ASTContext.h"<br>
#include "clang/AST/DeclObjC.h"<br>
+#include "clang/AST/TemplateBase.h"<br>
+#include "clang/AST/ExprCXX.h"<br>
+#include "clang/AST/DeclTemplate.h"<br>
#include "clang/AST/Type.h"<br>
+#include "llvm/ADT/SmallString.h"<br>
#include "llvm/Support/raw_ostream.h"<br>
<br>
using namespace clang;<br>
@@ -225,6 +229,11 @@<br>
return S;<br>
}<br>
<br>
+static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,<br>
+ QualType ToType, bool PrintTree,<br>
+ bool PrintFromType, bool ElideType,<br>
+ bool ShowColors, std::string &S);<br>
+<br>
void clang::FormatASTNodeDiagnosticArgument(<br>
DiagnosticsEngine::ArgumentKind Kind,<br>
intptr_t Val,<br>
@@ -244,6 +253,32 @@<br>
<br>
switch (Kind) {<br>
default: llvm_unreachable("unknown ArgumentKind");<br>
+ case DiagnosticsEngine::ak_qualtype_pair: {<br>
+ const TemplateDiffTypes &TDT = *reinterpret_cast<TemplateDiffTypes*>(Val);<br>
+ QualType FromType =<br>
+ QualType::getFromOpaquePtr(reinterpret_cast<void*>(TDT.FromType));<br>
+ QualType ToType =<br>
+ QualType::getFromOpaquePtr(reinterpret_cast<void*>(TDT.ToType));<br>
+<br>
+ if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree,<br>
+ TDT.PrintFromType, TDT.ElideType,<br>
+ TDT.ShowColors, S)) {<br>
+ NeedQuotes = !TDT.PrintTree;<br>
+ break;<br>
+ }<br>
+<br>
+ // Don't fall-back during tree printing. The caller will handle<br>
+ // this case.<br>
+ if (TDT.PrintTree)<br>
+ return;<br>
+<br>
+ // Attempting to do a templete diff on non-templates. Set the variables<br>
+ // and continue with regular type printing of the appropriate type.<br>
+ Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType;<br>
+ ModLen = 0;<br>
+ ArgLen = 0;<br>
+ // Fall through<br>
+ }<br>
case DiagnosticsEngine::ak_qualtype: {<br>
assert(ModLen == 0 && ArgLen == 0 &&<br>
"Invalid modifier for QualType argument");<br>
@@ -329,3 +364,901 @@<br>
if (NeedQuotes)<br>
Output.push_back('\'');<br>
}<br>
+<br>
+/// TemplateDiff - A class that constructs a pretty string for a pair of<br>
+/// QualTypes. For the pair of types, a diff tree will be created containing<br>
+/// all the information about the templates and template arguments. Afterwards,<br>
+/// the tree is transformed to a string according to the options passed in.<br>
+namespace {<br>
+class TemplateDiff {<br>
+ /// Context - The ASTContext which is used for comparing template arguments.<br>
+ ASTContext &Context;<br>
+<br>
+ /// Policy - Used during expression printing.<br>
+ PrintingPolicy Policy;<br>
+<br>
+ /// ElideType - Option to elide identical types.<br>
+ bool ElideType;<br>
+<br>
+ /// PrintTree - Format output string as a tree.<br>
+ bool PrintTree;<br>
+<br>
+ /// ShowColor - Diagnostics support color, so bolding will be used.<br>
+ bool ShowColor;<br>
+<br>
+ /// FromType - When single type printing is selected, this is the type to be<br>
+ /// be printed. When tree printing is selected, this type will show up first<br>
+ /// in the tree.<br>
+ QualType FromType;<br>
+<br>
+ /// ToType - The type that FromType is compared to. Only in tree printing<br>
+ /// will this type be outputed.<br>
+ QualType ToType;<br>
+<br>
+ /// Str - Storage for the output stream.<br>
+ llvm::SmallString<128> Str;<br>
+<br>
+ /// OS - The stream used to construct the output strings.<br>
+ llvm::raw_svector_ostream OS;<br>
+<br>
+ /// IsBold - Keeps track of the bold formatting for the output string.<br>
+ bool IsBold;<br>
+<br>
+ /// DiffTree - A tree representation the differences between two types.<br>
+ class DiffTree {<br>
+ /// DiffNode - The root node stores the original type. Each child node<br>
+ /// stores template arguments of their parents. For templated types, the<br>
+ /// template decl is also stored.<br>
+ struct DiffNode {<br>
+ /// NextNode - The index of the next sibling node or 0.<br>
+ unsigned NextNode;<br>
+<br>
+ /// ChildNode - The index of the first child node or 0.<br>
+ unsigned ChildNode;<br>
+<br>
+ /// ParentNode - The index of the parent node.<br>
+ unsigned ParentNode;<br>
+<br>
+ /// FromType, ToType - The type arguments.<br>
+ QualType FromType, ToType;<br>
+<br>
+ /// FromExpr, ToExpr - The expression arguments.<br>
+ Expr *FromExpr, *ToExpr;<br>
+<br>
+ /// FromTD, ToTD - The template decl for template template<br>
+ /// arguments or the type arguments that are templates.<br>
+ TemplateDecl *FromTD, *ToTD;<br>
+<br>
+ /// FromDefault, ToDefault - Whether the argument is a default argument.<br>
+ bool FromDefault, ToDefault;<br>
+<br>
+ /// Same - Whether the two arguments evaluate to the same value.<br>
+ bool Same;<br>
+<br>
+ DiffNode(unsigned ParentNode = 0)<br>
+ : NextNode(0), ChildNode(0), ParentNode(ParentNode),<br>
+ FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),<br>
+ FromDefault(false), ToDefault(false), Same(false) { }<br>
+ };<br>
+<br>
+ /// FlatTree - A flattened tree used to store the DiffNodes.<br>
+ llvm::SmallVector<DiffNode, 16> FlatTree;<br>
+<br>
+ /// CurrentNode - The index of the current node being used.<br>
+ unsigned CurrentNode;<br>
+<br>
+ /// NextFreeNode - The index of the next unused node. Used when creating<br>
+ /// child nodes.<br>
+ unsigned NextFreeNode;<br>
+<br>
+ /// ReadNode - The index of the current node being read.<br>
+ unsigned ReadNode;<br>
+<br>
+ public:<br>
+ DiffTree() :<br>
+ CurrentNode(0), NextFreeNode(1) {<br>
+ FlatTree.push_back(DiffNode());<br>
+ }<br>
+<br>
+ // Node writing functions.<br>
+ /// SetNode - Sets FromTD and ToTD of the current node.<br>
+ void SetNode(TemplateDecl *FromTD, TemplateDecl *ToTD) {<br>
+ FlatTree[CurrentNode].FromTD = FromTD;<br>
+ FlatTree[CurrentNode].ToTD = ToTD;<br>
+ }<br>
+<br>
+ /// SetNode - Sets FromType and ToType of the current node.<br>
+ void SetNode(QualType FromType, QualType ToType) {<br>
+ FlatTree[CurrentNode].FromType = FromType;<br>
+ FlatTree[CurrentNode].ToType = ToType;<br>
+ }<br>
+<br>
+ /// SetNode - Set FromExpr and ToExpr of the current node.<br>
+ void SetNode(Expr *FromExpr, Expr *ToExpr) {<br>
+ FlatTree[CurrentNode].FromExpr = FromExpr;<br>
+ FlatTree[CurrentNode].ToExpr = ToExpr;<br>
+ }<br>
+<br>
+ /// SetSame - Sets the same flag of the current node.<br>
+ void SetSame(bool Same) {<br>
+ FlatTree[CurrentNode].Same = Same;<br>
+ }<br>
+<br>
+ /// SetDefault - Sets FromDefault and ToDefault flags of the current node.<br>
+ void SetDefault(bool FromDefault, bool ToDefault) {<br>
+ FlatTree[CurrentNode].FromDefault = FromDefault;<br>
+ FlatTree[CurrentNode].ToDefault = ToDefault;<br>
+ }<br>
+<br>
+ /// Up - Changes the node to the parent of the current node.<br>
+ void Up() {<br>
+ CurrentNode = FlatTree[CurrentNode].ParentNode;<br>
+ }<br>
+<br>
+ /// AddNode - Adds a child node to the current node, then sets that node<br>
+ /// node as the current node.<br>
+ void AddNode() {<br>
+ FlatTree.push_back(DiffNode(CurrentNode));<br>
+ DiffNode &Node = FlatTree[CurrentNode];<br>
+ if (Node.ChildNode == 0) {<br>
+ // If a child node doesn't exist, add one.<br>
+ Node.ChildNode = NextFreeNode;<br>
+ } else {<br>
+ // If a child node exists, find the last child node and add a<br>
+ // next node to it.<br>
+ unsigned i;<br>
+ for (i = Node.ChildNode; FlatTree[i].NextNode != 0;<br>
+ i = FlatTree[i].NextNode) {<br>
+ }<br>
+ FlatTree[i].NextNode = NextFreeNode;<br>
+ }<br>
+ CurrentNode = NextFreeNode;<br>
+ ++NextFreeNode;<br>
+ }<br>
+<br>
+ // Node reading functions.<br>
+ /// StartTraverse - Prepares the tree for recursive traversal.<br>
+ void StartTraverse() {<br>
+ ReadNode = 0;<br>
+ CurrentNode = NextFreeNode;<br>
+ NextFreeNode = 0;<br>
+ }<br>
+<br>
+ /// Parent - Move the current read node to its parent.<br>
+ void Parent() {<br>
+ ReadNode = FlatTree[ReadNode].ParentNode;<br>
+ }<br>
+<br>
+ /// NodeIsTemplate - Returns true if a template decl is set, and types are<br>
+ /// set.<br>
+ bool NodeIsTemplate() {<br>
+ return (FlatTree[ReadNode].FromTD &&<br>
+ !FlatTree[ReadNode].ToType.isNull()) ||<br>
+ (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull());<br>
+ }<br>
+<br>
+ /// NodeIsQualType - Returns true if a Qualtype is set.<br>
+ bool NodeIsQualType() {<br>
+ return !FlatTree[ReadNode].FromType.isNull() ||<br>
+ !FlatTree[ReadNode].ToType.isNull();<br>
+ }<br>
+<br>
+ /// NodeIsExpr - Returns true if an expr is set.<br>
+ bool NodeIsExpr() {<br>
+ return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr;<br>
+ }<br>
+<br>
+ /// NodeIsTemplateTemplate - Returns true if the argument is a template<br>
+ /// template type.<br>
+ bool NodeIsTemplateTemplate() {<br>
+ return FlatTree[ReadNode].FromType.isNull() &&<br>
+ FlatTree[ReadNode].ToType.isNull() &&<br>
+ (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD);<br>
+ }<br>
+<br>
+ /// GetNode - Gets the FromType and ToType.<br>
+ void GetNode(QualType &FromType, QualType &ToType) {<br>
+ FromType = FlatTree[ReadNode].FromType;<br>
+ ToType = FlatTree[ReadNode].ToType;<br>
+ }<br>
+<br>
+ /// GetNode - Gets the FromExpr and ToExpr.<br>
+ void GetNode(Expr *&FromExpr, Expr *&ToExpr) {<br>
+ FromExpr = FlatTree[ReadNode].FromExpr;<br>
+ ToExpr = FlatTree[ReadNode].ToExpr;<br>
+ }<br>
+<br>
+ /// GetNode - Gets the FromTD and ToTD.<br>
+ void GetNode(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {<br>
+ FromTD = FlatTree[ReadNode].FromTD;<br>
+ ToTD = FlatTree[ReadNode].ToTD;<br>
+ }<br>
+<br>
+ /// NodeIsSame - Returns true the arguments are the same.<br>
+ bool NodeIsSame() {<br>
+ return FlatTree[ReadNode].Same;<br>
+ }<br>
+<br>
+ /// HasChildrend - Returns true if the node has children.<br>
+ bool HasChildren() {<br>
+ return FlatTree[ReadNode].ChildNode != 0;<br>
+ }<br>
+<br>
+ /// MoveToChild - Moves from the current node to its child.<br>
+ void MoveToChild() {<br>
+ ReadNode = FlatTree[ReadNode].ChildNode;<br>
+ }<br>
+<br>
+ /// AdvanceSibling - If there is a next sibling, advance to it and return<br>
+ /// true. Otherwise, return false.<br>
+ bool AdvanceSibling() {<br>
+ if (FlatTree[ReadNode].NextNode == 0)<br>
+ return false;<br>
+<br>
+ ReadNode = FlatTree[ReadNode].NextNode;<br>
+ return true;<br>
+ }<br>
+<br>
+ /// HasNextSibling - Return true if the node has a next sibling.<br>
+ bool HasNextSibling() {<br>
+ return FlatTree[ReadNode].NextNode != 0;<br>
+ }<br>
+<br>
+ /// FromDefault - Return true if the from argument is the default.<br>
+ bool FromDefault() {<br>
+ return FlatTree[ReadNode].FromDefault;<br>
+ }<br>
+<br>
+ /// ToDefault - Return true if the to argument is the default.<br>
+ bool ToDefault() {<br>
+ return FlatTree[ReadNode].ToDefault;<br>
+ }<br>
+<br>
+ /// Empty - Returns true if the tree has no information.<br>
+ bool Empty() {<br>
+ return !FlatTree[0].FromTD && !FlatTree[0].ToTD &&<br>
+ !FlatTree[0].FromExpr && !FlatTree[0].ToExpr &&<br>
+ FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull();<br>
+ }<br>
+ };<br>
+<br>
+ DiffTree Tree;<br>
+<br>
+ /// TSTiterator - an iterator that is used to enter a<br>
+ /// TemplateSpecializationType and read TemplateArguments inside template<br>
+ /// parameter packs in order with the rest of the TemplateArguments.<br>
+ struct TSTiterator {<br>
+ typedef const TemplateArgument& reference;<br>
+ typedef const TemplateArgument* pointer;<br>
+<br>
+ /// TST - the template specialization whose arguments this iterator<br>
+ /// traverse over.<br>
+ const TemplateSpecializationType *TST;<br>
+<br>
+ /// Index - the index of the template argument in TST.<br>
+ unsigned Index;<br>
+<br>
+ /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA<br>
+ /// points to a TemplateArgument within a parameter pack.<br>
+ TemplateArgument::pack_iterator CurrentTA;<br>
+<br>
+ /// EndTA - the end iterator of a parameter pack<br>
+ TemplateArgument::pack_iterator EndTA;<br>
+<br>
+ /// TSTiterator - Constructs an iterator and sets it to the first template<br>
+ /// argument.<br>
+ TSTiterator(const TemplateSpecializationType *TST)<br>
+ : TST(TST), Index(0), CurrentTA(0), EndTA(0) {<br>
+ if (isEnd()) return;<br>
+<br>
+ // Set to first template argument. If not a parameter pack, done.<br>
+ TemplateArgument TA = TST->getArg(0);<br>
+ if (TA.getKind() != TemplateArgument::Pack) return;<br>
+<br>
+ // Start looking into the parameter pack.<br>
+ CurrentTA = TA.pack_begin();<br>
+ EndTA = TA.pack_end();<br>
+<br>
+ // Found a valid template argument.<br>
+ if (CurrentTA != EndTA) return;<br>
+<br>
+ // Parameter pack is empty, use the increment to get to a valid<br>
+ // template argument.<br>
+ ++(*this);<br>
+ }<br>
+<br>
+ /// isEnd - Returns true if the iterator is one past the end.<br>
+ bool isEnd() const {<br>
+ return Index == TST->getNumArgs();<br>
+ }<br>
+<br>
+ /// &operator++ - Increment the iterator to the next template argument.<br>
+ TSTiterator &operator++() {<br>
+ assert(!isEnd() && "Iterator incremented past end of arguments.");<br>
+<br>
+ // If in a parameter pack, advance in the parameter pack.<br>
+ if (CurrentTA != EndTA) {<br>
+ ++CurrentTA;<br>
+ if (CurrentTA != EndTA)<br>
+ return *this;<br>
+ }<br>
+<br>
+ // Loop until a template argument is found, or the end is reached.<br>
+ while (true) {<br>
+ // Advance to the next template argument. Break if reached the end.<br>
+ if (++Index == TST->getNumArgs()) break;<br>
+<br>
+ // If the TemplateArgument is not a parameter pack, done.<br>
+ TemplateArgument TA = TST->getArg(Index);<br>
+ if (TA.getKind() != TemplateArgument::Pack) break;<br>
+<br>
+ // Handle parameter packs.<br>
+ CurrentTA = TA.pack_begin();<br>
+ EndTA = TA.pack_end();<br>
+<br>
+ // If the parameter pack is empty, try to advance again.<br>
+ if (CurrentTA != EndTA) break;<br>
+ }<br>
+ return *this;<br>
+ }<br>
+<br>
+ /// operator* - Returns the appropriate TemplateArgument.<br>
+ reference operator*() const {<br>
+ assert(!isEnd() && "Index exceeds number of arguments.");<br>
+ if (CurrentTA == EndTA)<br>
+ return TST->getArg(Index);<br>
+ else<br>
+ return *CurrentTA;<br>
+ }<br>
+<br>
+ /// operator-> - Allow access to the underlying TemplateArgument.<br>
+ pointer operator->() const {<br>
+ return &operator*();<br>
+ }<br>
+ };<br>
+<br>
+ // These functions build up the template diff tree, including functions to<br>
+ // retrieve and compare template arguments.<br>
+<br>
+ static const TemplateSpecializationType * GetTemplateSpecializationType(<br>
+ ASTContext &Context, QualType Ty) {<br>
+ if (const TemplateSpecializationType *TST =<br>
+ Ty->getAs<TemplateSpecializationType>())<br>
+ return TST;<br>
+<br>
+ const RecordType *RT = Ty->getAs<RecordType>();<br>
+<br>
+ if (!RT)<br>
+ return 0;<br>
+<br>
+ const ClassTemplateSpecializationDecl *CTSD =<br>
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());<br>
+<br>
+ if (!CTSD)<br>
+ return 0;<br>
+<br>
+ Ty = Context.getTemplateSpecializationType(<br>
+ TemplateName(CTSD->getSpecializedTemplate()),<br>
+ CTSD->getTemplateArgs().data(),<br>
+ CTSD->getTemplateArgs().size(),<br>
+ Ty.getCanonicalType());<br>
+<br>
+ return Ty->getAs<TemplateSpecializationType>();<br>
+ }<br>
+<br>
+ /// DiffTemplate - recursively visits template arguments and stores the<br>
+ /// argument info into a tree.<br>
+ void DiffTemplate(const TemplateSpecializationType *FromTST,<br>
+ const TemplateSpecializationType *ToTST) {<br>
+ // Begin descent into diffing template tree.<br>
+ TemplateParameterList *Params =<br>
+ FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();<br>
+ unsigned TotalArgs = 0;<br>
+ for (TSTiterator FromIter(FromTST), ToIter(ToTST);<br>
+ !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {<br>
+ Tree.AddNode();<br>
+<br>
+ // Get the parameter at index TotalArgs. If index is larger<br>
+ // than the total number of parameters, then there is an<br>
+ // argument pack, so re-use the last parameter.<br>
+ NamedDecl *ParamND = Params->getParam(<br>
+ (TotalArgs < Params->size()) ? TotalArgs<br>
+ : Params->size() - 1);<br>
+ // Handle Types<br>
+ if (TemplateTypeParmDecl *DefaultTTPD =<br>
+ dyn_cast<TemplateTypeParmDecl>(ParamND)) {<br>
+ QualType FromType, ToType;<br>
+ GetType(FromIter, DefaultTTPD, FromType);<br>
+ GetType(ToIter, DefaultTTPD, ToType);<br>
+ Tree.SetNode(FromType, ToType);<br>
+ Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),<br>
+ ToIter.isEnd() && !ToType.isNull());<br>
+ if (!FromType.isNull() && !ToType.isNull()) {<br>
+ if (Context.hasSameType(FromType, ToType)) {<br>
+ Tree.SetSame(true);<br>
+ } else {<br>
+ const TemplateSpecializationType *FromArgTST =<br>
+ GetTemplateSpecializationType(Context, FromType);<br>
+ const TemplateSpecializationType *ToArgTST =<br>
+ GetTemplateSpecializationType(Context, ToType);<br>
+<br>
+ if (FromArgTST && ToArgTST) {<br>
+ bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST);<br>
+ if (SameTemplate) {<br>
+ Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),<br>
+ ToArgTST->getTemplateName().getAsTemplateDecl());<br>
+ DiffTemplate(FromArgTST, ToArgTST);<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+ // Handle Expressions<br>
+ if (NonTypeTemplateParmDecl *DefaultNTTPD =<br>
+ dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {<br>
+ Expr *FromExpr, *ToExpr;<br>
+ GetExpr(FromIter, DefaultNTTPD, FromExpr);<br>
+ GetExpr(ToIter, DefaultNTTPD, ToExpr);<br>
+ Tree.SetNode(FromExpr, ToExpr);<br>
+ Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));<br>
+ Tree.SetDefault(FromIter.isEnd() && FromExpr,<br>
+ ToIter.isEnd() && ToExpr);<br>
+ }<br>
+<br>
+ // Handle Templates<br>
+ if (TemplateTemplateParmDecl *DefaultTTPD =<br>
+ dyn_cast<TemplateTemplateParmDecl>(ParamND)) {<br>
+ TemplateDecl *FromDecl, *ToDecl;<br>
+ GetTemplateDecl(FromIter, DefaultTTPD, FromDecl);<br>
+ GetTemplateDecl(ToIter, DefaultTTPD, ToDecl);<br>
+ Tree.SetNode(FromDecl, ToDecl);<br>
+ Tree.SetSame(FromDecl && ToDecl &&<br>
+ FromDecl->getIdentifier() == ToDecl->getIdentifier());<br>
+ }<br>
+<br>
+ if (!FromIter.isEnd()) ++FromIter;<br>
+ if (!ToIter.isEnd()) ++ToIter;<br>
+ Tree.Up();<br>
+ }<br>
+ }<br>
+<br>
+ /// hasSameTemplate - Returns true if both types are specialized from the<br>
+ /// same template declaration. If they come from different template aliases,<br>
+ /// do a parallel ascension search to determine the highest template alias in<br>
+ /// common and set the arguments to them.<br>
+ static bool hasSameTemplate(const TemplateSpecializationType *&FromTST,<br>
+ const TemplateSpecializationType *&ToTST) {<br>
+ // Check the top templates if they are the same.<br>
+ if (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==<br>
+ ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier())<br>
+ return true;<br>
+<br>
+ // Create vectors of template aliases.<br>
+ SmallVector<const TemplateSpecializationType*, 1> FromTemplateList,<br>
+ ToTemplateList;<br>
+<br>
+ const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST;<br>
+ FromTemplateList.push_back(FromTST);<br>
+ ToTemplateList.push_back(ToTST);<br>
+<br>
+ // Dump every template alias into the vectors.<br>
+ while (TempFromTST->isTypeAlias()) {<br>
+ TempFromTST =<br>
+ TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>();<br>
+ if (!TempFromTST)<br>
+ break;<br>
+ FromTemplateList.push_back(TempFromTST);<br>
+ }<br>
+ while (TempToTST->isTypeAlias()) {<br>
+ TempToTST =<br>
+ TempToTST->getAliasedType()->getAs<TemplateSpecializationType>();<br>
+ if (!TempToTST)<br>
+ break;<br>
+ ToTemplateList.push_back(TempToTST);<br>
+ }<br>
+<br>
+ SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator<br>
+ FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),<br>
+ ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();<br>
+<br>
+ // Check if the lowest template types are the same. If not, return.<br>
+ if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=<br>
+ (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())<br>
+ return false;<br>
+<br>
+ // Begin searching up the template aliases. The bottom most template<br>
+ // matches so move up until one pair does not match. Use the template<br>
+ // right before that one.<br>
+ for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) {<br>
+ if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=<br>
+ (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())<br>
+ break;<br>
+ }<br>
+<br>
+ FromTST = FromIter[-1];<br>
+ ToTST = ToIter[-1];<br>
+<br>
+ return true;<br>
+ }<br>
+<br>
+ /// GetType - Retrieves the template type arguments, including default<br>
+ /// arguments.<br>
+ void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD,<br>
+ QualType &ArgType) {<br>
+ ArgType = QualType();<br>
+ bool isVariadic = DefaultTTPD->isParameterPack();<br>
+<br>
+ if (!Iter.isEnd())<br>
+ ArgType = Iter->getAsType();<br>
+ else if (!isVariadic)<br>
+ ArgType = DefaultTTPD->getDefaultArgument();<br>
+ };<br>
+<br>
+ /// GetExpr - Retrieves the template expression argument, including default<br>
+ /// arguments.<br>
+ void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD,<br>
+ Expr *&ArgExpr) {<br>
+ ArgExpr = 0;<br>
+ bool isVariadic = DefaultNTTPD->isParameterPack();<br>
+<br>
+ if (!Iter.isEnd())<br>
+ ArgExpr = Iter->getAsExpr();<br>
+ else if (!isVariadic)<br>
+ ArgExpr = DefaultNTTPD->getDefaultArgument();<br>
+<br>
+ if (ArgExpr)<br>
+ while (SubstNonTypeTemplateParmExpr *SNTTPE =<br>
+ dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr))<br>
+ ArgExpr = SNTTPE->getReplacement();<br>
+ }<br>
+<br>
+ /// GetTemplateDecl - Retrieves the template template arguments, including<br>
+ /// default arguments.<br>
+ void GetTemplateDecl(const TSTiterator &Iter,<br>
+ TemplateTemplateParmDecl *DefaultTTPD,<br>
+ TemplateDecl *&ArgDecl) {<br>
+ ArgDecl = 0;<br>
+ bool isVariadic = DefaultTTPD->isParameterPack();<br>
+<br>
+ TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();<br>
+ TemplateDecl *DefaultTD = TA.getAsTemplate().getAsTemplateDecl();<br>
+<br>
+ if (!Iter.isEnd())<br>
+ ArgDecl = Iter->getAsTemplate().getAsTemplateDecl();<br>
+ else if (!isVariadic)<br>
+ ArgDecl = DefaultTD;<br>
+ }<br>
+<br>
+ /// IsEqualExpr - Returns true if the expressions evaluate to the same value.<br>
+ static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {<br>
+ if (FromExpr == ToExpr)<br>
+ return true;<br>
+<br>
+ if (!FromExpr || !ToExpr)<br>
+ return false;<br>
+<br>
+ FromExpr = FromExpr->IgnoreParens();<br>
+ ToExpr = ToExpr->IgnoreParens();<br>
+<br>
+ DeclRefExpr *FromDRE = dyn_cast<DeclRefExpr>(FromExpr),<br>
+ *ToDRE = dyn_cast<DeclRefExpr>(ToExpr);<br>
+<br>
+ if (FromDRE || ToDRE) {<br>
+ if (!FromDRE || !ToDRE)<br>
+ return false;<br>
+ return FromDRE->getDecl() == ToDRE->getDecl();<br>
+ }<br>
+<br>
+ Expr::EvalResult FromResult, ToResult;<br>
+ if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||<br>
+ !ToExpr->EvaluateAsRValue(ToResult, Context))<br>
+ assert(0 && "Template arguments must be known at compile time.");<br>
+<br>
+ APValue &FromVal = FromResult.Val;<br>
+ APValue &ToVal = ToResult.Val;<br>
+<br>
+ if (FromVal.getKind() != ToVal.getKind()) return false;<br>
+<br>
+ switch (FromVal.getKind()) {<br>
+ case APValue::Int:<br>
+ return FromVal.getInt() == ToVal.getInt();<br>
+ case APValue::LValue: {<br>
+ APValue::LValueBase FromBase = FromVal.getLValueBase();<br>
+ APValue::LValueBase ToBase = ToVal.getLValueBase();<br>
+ if (FromBase.isNull() && ToBase.isNull())<br>
+ return true;<br>
+ if (FromBase.isNull() || ToBase.isNull())<br>
+ return false;<br>
+ return FromBase.get<const ValueDecl*>() ==<br>
+ ToBase.get<const ValueDecl*>();<br>
+ }<br>
+ case APValue::MemberPointer:<br>
+ return FromVal.getMemberPointerDecl() == ToVal.getMemberPointerDecl();<br>
+ default:<br>
+ llvm_unreachable("Unknown template argument expression.");<br>
+ }<br>
+ }<br>
+<br>
+ // These functions converts the tree representation of the template<br>
+ // differences into the internal character vector.<br>
+<br>
+ /// TreeToString - Converts the Tree object into a character stream which<br>
+ /// will later be turned into the output string.<br>
+ void TreeToString(int Indent = 1) {<br>
+ if (PrintTree) {<br>
+ OS << '\n';<br>
+ for (int i = 0; i < Indent; ++i)<br>
+ OS << " ";<br>
+ ++Indent;<br>
+ }<br>
+<br>
+ // Handle cases where the difference is not templates with different<br>
+ // arguments.<br>
+ if (!Tree.NodeIsTemplate()) {<br>
+ if (Tree.NodeIsQualType()) {<br>
+ QualType FromType, ToType;<br>
+ Tree.GetNode(FromType, ToType);<br>
+ PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),<br>
+ Tree.NodeIsSame());<br>
+ return;<br>
+ }<br>
+ if (Tree.NodeIsExpr()) {<br>
+ Expr *FromExpr, *ToExpr;<br>
+ Tree.GetNode(FromExpr, ToExpr);<br>
+ PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),<br>
+ Tree.NodeIsSame());<br>
+ return;<br>
+ }<br>
+ if (Tree.NodeIsTemplateTemplate()) {<br>
+ TemplateDecl *FromTD, *ToTD;<br>
+ Tree.GetNode(FromTD, ToTD);<br>
+ PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),<br>
+ Tree.ToDefault(), Tree.NodeIsSame());<br>
+ return;<br>
+ }<br>
+ llvm_unreachable("Unable to deduce template difference.");<br>
+ }<br>
+<br>
+ // Node is root of template. Recurse on children.<br>
+ TemplateDecl *FromTD, *ToTD;<br>
+ Tree.GetNode(FromTD, ToTD);<br>
+<br>
+ assert(Tree.HasChildren() && "Template difference not found in diff tree.");<br>
+<br>
+ OS << FromTD->getNameAsString() << '<';<br>
+ Tree.MoveToChild();<br>
+ unsigned NumElideArgs = 0;<br>
+ do {<br>
+ if (ElideType) {<br>
+ if (Tree.NodeIsSame()) {<br>
+ ++NumElideArgs;<br>
+ continue;<br>
+ }<br>
+ if (NumElideArgs > 0) {<br>
+ PrintElideArgs(NumElideArgs, Indent);<br>
+ NumElideArgs = 0;<br>
+ OS << ", ";<br>
+ }<br>
+ }<br>
+ TreeToString(Indent);<br>
+ if (Tree.HasNextSibling())<br>
+ OS << ", ";<br>
+ } while (Tree.AdvanceSibling());<br>
+ if (NumElideArgs > 0)<br>
+ PrintElideArgs(NumElideArgs, Indent);<br>
+<br>
+ Tree.Parent();<br>
+ OS << ">";<br>
+ }<br>
+<br>
+ // To signal to the text printer that a certain text needs to be bolded,<br>
+ // a special character is injected into the character stream which the<br>
+ // text printer will later strip out.<br>
+<br>
+ /// Bold - Start bolding text.<br>
+ void Bold() {<br>
+ assert(!IsBold && "Attempting to bold text that is already bold.");<br>
+ IsBold = true;<br>
+ if (ShowColor)<br>
+ OS << ToggleHighlight;<br>
+ }<br>
+<br>
+ /// Unbold - Stop bolding text.<br>
+ void Unbold() {<br>
+ assert(IsBold && "Attempting to remove bold from unbold text.");<br>
+ IsBold = false;<br>
+ if (ShowColor)<br>
+ OS << ToggleHighlight;<br>
+ }<br>
+<br>
+ // Functions to print out the arguments and highlighting the difference.<br>
+<br>
+ /// PrintTypeNames - prints the typenames, bolding differences. Will detect<br>
+ /// typenames that are the same and attempt to disambiguate them by using<br>
+ /// canonical typenames.<br>
+ void PrintTypeNames(QualType FromType, QualType ToType,<br>
+ bool FromDefault, bool ToDefault, bool Same) {<br>
+ assert((!FromType.isNull() || !ToType.isNull()) &&<br>
+ "Only one template argument may be missing.");<br>
+<br>
+ if (Same) {<br>
+ OS << FromType.getAsString();<br>
+ return;<br>
+ }<br>
+<br>
+ std::string FromTypeStr = FromType.isNull() ? "(no argument)"<br>
+ : FromType.getAsString();<br>
+ std::string ToTypeStr = ToType.isNull() ? "(no argument)"<br>
+ : ToType.getAsString();<br>
+ // Switch to canonical typename if it is better.<br>
+ // TODO: merge this with other aka printing above.<br>
+ if (FromTypeStr == ToTypeStr) {<br>
+ std::string FromCanTypeStr = FromType.getCanonicalType().getAsString();<br>
+ std::string ToCanTypeStr = ToType.getCanonicalType().getAsString();<br>
+ if (FromCanTypeStr != ToCanTypeStr) {<br>
+ FromTypeStr = FromCanTypeStr;<br>
+ ToTypeStr = ToCanTypeStr;<br>
+ }<br>
+ }<br>
+<br>
+ if (PrintTree) OS << '[';<br>
+ OS << (FromDefault ? "(default) " : "");<br>
+ Bold();<br>
+ OS << FromTypeStr;<br>
+ Unbold();<br>
+ if (PrintTree) {<br>
+ OS << " != " << (ToDefault ? "(default) " : "");<br>
+ Bold();<br>
+ OS << ToTypeStr;<br>
+ Unbold();<br>
+ OS << "]";<br>
+ }<br>
+ return;<br>
+ }<br>
+<br>
+ /// PrintExpr - Prints out the expr template arguments, highlighting argument<br>
+ /// differences.<br>
+ void PrintExpr(const Expr *FromExpr, const Expr *ToExpr,<br>
+ bool FromDefault, bool ToDefault, bool Same) {<br>
+ assert((FromExpr || ToExpr) &&<br>
+ "Only one template argument may be missing.");<br>
+ if (Same) {<br>
+ PrintExpr(FromExpr);<br>
+ } else if (!PrintTree) {<br>
+ OS << (FromDefault ? "(default) " : "");<br>
+ Bold();<br>
+ PrintExpr(FromExpr);<br>
+ Unbold();<br>
+ } else {<br>
+ OS << (FromDefault ? "[(default) " : "[");<br>
+ Bold();<br>
+ PrintExpr(FromExpr);<br>
+ Unbold();<br>
+ OS << " != " << (ToDefault ? "(default) " : "");<br>
+ Bold();<br>
+ PrintExpr(ToExpr);<br>
+ Unbold();<br>
+ OS << ']';<br>
+ }<br>
+ }<br>
+<br>
+ /// PrintExpr - Actual formatting and printing of expressions.<br>
+ void PrintExpr(const Expr *E) {<br>
+ if (!E)<br>
+ OS << "(no argument)";<br>
+ else<br>
+ E->printPretty(OS, Context, 0, Policy); return;<br>
+ }<br>
+<br>
+ /// PrintTemplateTemplate - Handles printing of template template arguments,<br>
+ /// highlighting argument differences.<br>
+ void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD,<br>
+ bool FromDefault, bool ToDefault, bool Same) {<br>
+ assert((FromTD || ToTD) && "Only one template argument may be missing.");<br>
+ if (Same) {<br>
+ OS << "template " << FromTD->getNameAsString();<br>
+ } else if (!PrintTree) {<br>
+ OS << (FromDefault ? "(default) template " : "template ");<br>
+ Bold();<br>
+ OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");<br>
+ Unbold();<br>
+ } else {<br>
+ OS << (FromDefault ? "[(default) template " : "[template ");<br>
+ Bold();<br>
+ OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");<br>
+ Unbold();<br>
+ OS << " != " << (ToDefault ? "(default) template " : "template ");<br>
+ Bold();<br>
+ OS << (ToTD ? ToTD->getNameAsString() : "(no argument)");<br>
+ Unbold();<br>
+ OS << ']';<br>
+ }<br>
+ }<br>
+<br>
+ // Prints the appropriate placeholder for elided template arguments.<br>
+ void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) {<br>
+ if (PrintTree) {<br>
+ OS << '\n';<br>
+ for (unsigned i = 0; i < Indent; ++i)<br>
+ OS << " ";<br>
+ }<br>
+ if (NumElideArgs == 0) return;<br>
+ if (NumElideArgs == 1)<br>
+ OS << "[...]";<br>
+ else<br>
+ OS << "[" << NumElideArgs << " * ...]";<br>
+ }<br>
+<br>
+public:<br>
+<br>
+ TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,<br>
+ bool PrintTree, bool PrintFromType, bool ElideType,<br>
+ bool ShowColor)<br>
+ : Context(Context),<br>
+ Policy(Context.getLangOpts()),<br>
+ ElideType(ElideType),<br>
+ PrintTree(PrintTree),<br>
+ ShowColor(ShowColor),<br>
+ // When printing a single type, the FromType is the one printed.<br>
+ FromType(PrintFromType ? FromType : ToType),<br>
+ ToType(PrintFromType ? ToType : FromType),<br>
+ OS(Str),<br>
+ IsBold(false) {<br>
+ }<br>
+<br>
+ /// DiffTemplate - Start the template type diffing.<br>
+ void DiffTemplate() {<br>
+ const TemplateSpecializationType *FromOrigTST =<br>
+ GetTemplateSpecializationType(Context, FromType);<br>
+ const TemplateSpecializationType *ToOrigTST =<br>
+ GetTemplateSpecializationType(Context, ToType);<br>
+<br>
+ // Only checking templates.<br>
+ if (!FromOrigTST || !ToOrigTST)<br>
+ return;<br>
+<br>
+ // Different base templates.<br>
+ if (!hasSameTemplate(FromOrigTST, ToOrigTST)) {<br>
+ return;<br>
+ }<br>
+<br>
+ Tree.SetNode(FromType, ToType);<br>
+<br>
+ // Same base template, but different arguments.<br>
+ Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),<br>
+ ToOrigTST->getTemplateName().getAsTemplateDecl());<br>
+<br>
+ DiffTemplate(FromOrigTST, ToOrigTST);<br>
+ };<br>
+<br>
+ /// MakeString - When the two types given are templated types with the same<br>
+ /// base template, a string representation of the type difference will be<br>
+ /// loaded into S and return true. Otherwise, return false.<br>
+ bool MakeString(std::string &S) {<br>
+ Tree.StartTraverse();<br>
+ if (Tree.Empty())<br>
+ return false;<br>
+<br>
+ TreeToString();<br>
+ assert(!IsBold && "Bold is applied to end of string.");<br>
+ S = OS.str();<br>
+ return true;<br>
+ }<br>
+}; // end class TemplateDiff<br>
+} // end namespace<br>
+<br>
+/// FormatTemplateTypeDiff - A helper static function to start the template<br>
+/// diff and return the properly formatted string. Returns true if the diff<br>
+/// is successful.<br>
+static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,<br>
+ QualType ToType, bool PrintTree,<br>
+ bool PrintFromType, bool ElideType,<br>
+ bool ShowColors, std::string &S) {<br>
+ if (PrintTree)<br>
+ PrintFromType = true;<br>
+ TemplateDiff TD(Context, FromType, ToType, PrintTree, PrintFromType,<br>
+ ElideType, ShowColors);<br>
+ TD.DiffTemplate();<br>
+ return TD.MakeString(S);<br>
+}<br>
<br>
Modified: cfe/trunk/lib/Basic/Diagnostic.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)<br>
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Tue Jun 26 13:18:47 2012<br>
@@ -48,6 +48,9 @@<br>
ErrorsAsFatal = false;<br>
SuppressSystemWarnings = false;<br>
SuppressAllDiagnostics = false;<br>
+ ElideType = true;<br>
+ PrintTemplateTree = false;<br>
+ ShowColors = false;<br>
ShowOverloads = Ovl_All;<br>
ExtBehavior = Ext_Ignore;<br>
<br>
@@ -660,6 +663,8 @@<br>
/// QualTypeVals - Pass a vector of arrays so that QualType names can be<br>
/// compared to see if more information is needed to be printed.<br>
SmallVector<intptr_t, 2> QualTypeVals;<br>
+ SmallVector<char, 64> Tree;<br>
+<br>
for (unsigned i = 0, e = getNumArgs(); i < e; ++i)<br>
if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)<br>
QualTypeVals.push_back(getRawArg(i));<br>
@@ -711,7 +716,20 @@<br>
assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");<br>
unsigned ArgNo = *DiagStr++ - '0';<br>
<br>
+ // Only used for type diffing.<br>
+ unsigned ArgNo2 = ArgNo;<br>
+<br>
DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);<br>
+ if (Kind == DiagnosticsEngine::ak_qualtype &&<br>
+ ModifierIs(Modifier, ModifierLen, "diff")) {<br>
+ Kind = DiagnosticsEngine::ak_qualtype_pair;<br>
+ assert(*DiagStr == ',' && isdigit(*(DiagStr + 1)) &&<br>
+ "Invalid format for diff modifier");<br>
+ ++DiagStr; // Comma.<br>
+ ArgNo2 = *DiagStr++ - '0';<br>
+ assert(getArgKind(ArgNo2) == DiagnosticsEngine::ak_qualtype &&<br>
+ "Second value of type diff must be a qualtype");<br>
+ }<br>
<br>
switch (Kind) {<br>
// ---- STRINGS ----<br>
@@ -796,18 +814,77 @@<br>
FormattedArgs.data(), FormattedArgs.size(),<br>
OutStr, QualTypeVals);<br>
break;<br>
+ case DiagnosticsEngine::ak_qualtype_pair:<br>
+ // Create a struct with all the info needed for printing.<br>
+ TemplateDiffTypes TDT;<br>
+ TDT.FromType = getRawArg(ArgNo);<br>
+ TDT.ToType = getRawArg(ArgNo2);<br>
+ TDT.ElideType = getDiags()->ElideType;<br>
+ TDT.ShowColors = getDiags()->ShowColors;<br>
+ intptr_t val = reinterpret_cast<intptr_t>(&TDT);<br>
+<br>
+ // Print the tree.<br>
+ if (getDiags()->PrintTemplateTree) {<br>
+ TDT.PrintFromType = true;<br>
+ TDT.PrintTree = true;<br>
+ getDiags()->ConvertArgToString(Kind, val,<br>
+ Modifier, ModifierLen,<br>
+ Argument, ArgumentLen,<br>
+ FormattedArgs.data(),<br>
+ FormattedArgs.size(),<br>
+ Tree, QualTypeVals);<br>
+ // If there is no tree information, fall back to regular printing.<br>
+ if (!Tree.empty())<br>
+ break;<br>
+ }<br>
+<br>
+ // Non-tree printing, also the fall-back when tree printing fails.<br>
+ // The fall-back is triggered when the types compared are not templates.<br>
+ const char *ArgumentEnd = Argument + ArgumentLen;<br>
+ const char *FirstPipe = ScanFormat(Argument, ArgumentEnd, '|');<br>
+ const char *SecondPipe = ScanFormat(FirstPipe + 1, ArgumentEnd, '|');<br>
+<br>
+ // Append before text<br>
+ FormatDiagnostic(Argument, FirstPipe, OutStr);<br>
+<br>
+ // Append first type<br>
+ TDT.PrintTree = false;<br>
+ TDT.PrintFromType = true;<br>
+ getDiags()->ConvertArgToString(Kind, val,<br>
+ Modifier, ModifierLen,<br>
+ Argument, ArgumentLen,<br>
+ FormattedArgs.data(), FormattedArgs.size(),<br>
+ OutStr, QualTypeVals);<br>
+ // Append middle text<br>
+ FormatDiagnostic(FirstPipe + 1, SecondPipe, OutStr);<br>
+<br>
+ // Append second type<br>
+ TDT.PrintFromType = false;<br>
+ getDiags()->ConvertArgToString(Kind, val,<br>
+ Modifier, ModifierLen,<br>
+ Argument, ArgumentLen,<br>
+ FormattedArgs.data(), FormattedArgs.size(),<br>
+ OutStr, QualTypeVals);<br>
+ // Append end text<br>
+ FormatDiagnostic(SecondPipe + 1, ArgumentEnd, OutStr);<br>
+ break;<br>
}<br>
<br>
// Remember this argument info for subsequent formatting operations. Turn<br>
// std::strings into a null terminated string to make it be the same case as<br>
// all the other ones.<br>
- if (Kind != DiagnosticsEngine::ak_std_string)<br>
+ if (Kind == DiagnosticsEngine::ak_qualtype_pair)<br>
+ continue;<br>
+ else if (Kind != DiagnosticsEngine::ak_std_string)<br>
FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));<br>
else<br>
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,<br>
(intptr_t)getArgStdStr(ArgNo).c_str()));<br>
<br>
}<br>
+<br>
+ // Append the type tree to the end of the diagnostics.<br>
+ OutStr.append(Tree.begin(), Tree.end());<br>
}<br>
<br>
StoredDiagnostic::StoredDiagnostic() { }<br>
<br>
Modified: cfe/trunk/lib/Driver/Tools.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Driver/Tools.cpp (original)<br>
+++ cfe/trunk/lib/Driver/Tools.cpp Tue Jun 26 13:18:47 2012<br>
@@ -2203,6 +2203,8 @@<br>
Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);<br>
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);<br>
Args.AddLastArg(CmdArgs, options::OPT_faltivec);<br>
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);<br>
+ Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);<br>
<br>
// Report and error for -faltivec on anything other then PowerPC.<br>
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))<br>
<br>
Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)<br>
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Jun 26 13:18:47 2012<br>
@@ -1349,6 +1349,8 @@<br>
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);<br>
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);<br>
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);<br>
+ Opts.ElideType = !Args.hasArg(OPT_fno_elide_type);<br>
+ Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree);<br>
Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);<br>
Opts.MacroBacktraceLimit<br>
= Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,<br>
<br>
Modified: cfe/trunk/lib/Frontend/TextDiagnostic.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/TextDiagnostic.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/TextDiagnostic.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Frontend/TextDiagnostic.cpp (original)<br>
+++ cfe/trunk/lib/Frontend/TextDiagnostic.cpp Tue Jun 26 13:18:47 2012<br>
@@ -31,12 +31,29 @@<br>
raw_ostream::GREEN;<br>
static const enum raw_ostream::Colors warningColor =<br>
raw_ostream::MAGENTA;<br>
+static const enum raw_ostream::Colors templateColor =<br>
+ raw_ostream::CYAN;<br>
static const enum raw_ostream::Colors errorColor = raw_ostream::RED;<br>
static const enum raw_ostream::Colors fatalColor = raw_ostream::RED;<br>
// Used for changing only the bold attribute.<br>
static const enum raw_ostream::Colors savedColor =<br>
raw_ostream::SAVEDCOLOR;<br>
<br>
+/// \brief Add highlights to differences in template strings.<br>
+static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,<br>
+ bool &Normal) {<br>
+ for (unsigned i = 0, e = Str.size(); i < e; ++i)<br>
+ if (Str[i] != ToggleHighlight) {<br>
+ OS << Str[i];<br>
+ } else {<br>
+ if (Normal)<br>
+ OS.changeColor(templateColor, true);<br>
+ else<br>
+ OS.resetColor();<br>
+ Normal = !Normal;<br>
+ }<br>
+}<br>
+<br>
/// \brief Number of spaces to indent when word-wrapping.<br>
const unsigned WordWrapIndentation = 6;<br>
<br>
@@ -578,6 +595,7 @@<br>
unsigned Column = 0,<br>
unsigned Indentation = WordWrapIndentation) {<br>
const unsigned Length = std::min(Str.find('\n'), Str.size());<br>
+ bool TextNormal = true;<br>
<br>
// The string used to indent each line.<br>
SmallString<16> IndentStr;<br>
@@ -601,7 +619,8 @@<br>
OS << ' ';<br>
Column += 1;<br>
}<br>
- OS << Str.substr(WordStart, WordLength);<br>
+ applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),<br>
+ TextNormal);<br>
Column += WordLength;<br>
continue;<br>
}<br>
@@ -610,13 +629,16 @@<br>
// line.<br>
OS << '\n';<br>
OS.write(&IndentStr[0], Indentation);<br>
- OS << Str.substr(WordStart, WordLength);<br>
+ applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),<br>
+ TextNormal);<br>
Column = Indentation + WordLength;<br>
Wrapped = true;<br>
}<br>
<br>
// Append any remaning text from the message with its existing formatting.<br>
- OS << Str.substr(Length);<br>
+ applyTemplateHighlighting(OS, Str.substr(Length), TextNormal);<br>
+<br>
+ assert(TextNormal && "Text highlighted at end of diagnostic message.");<br>
<br>
return Wrapped;<br>
}<br>
<br>
Modified: cfe/trunk/lib/Frontend/Warnings.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Warnings.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Warnings.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Frontend/Warnings.cpp (original)<br>
+++ cfe/trunk/lib/Frontend/Warnings.cpp Tue Jun 26 13:18:47 2012<br>
@@ -53,7 +53,11 @@<br>
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);<br>
Diags.setShowOverloads(<br>
static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads));<br>
-<br>
+<br>
+ Diags.setElideType(Opts.ElideType);<br>
+ Diags.setPrintTemplateTree(Opts.ShowTemplateTree);<br>
+ Diags.setShowColors(Opts.ShowColors);<br>
+<br>
// Handle -ferror-limit<br>
if (Opts.ErrorLimit)<br>
Diags.setErrorLimit(Opts.ErrorLimit);<br>
<br>
Modified: cfe/trunk/test/Misc/diag-aka-types.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/diag-aka-types.cpp?rev=159216&r1=159215&r2=159216&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/diag-aka-types.cpp?rev=159216&r1=159215&r2=159216&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Misc/diag-aka-types.cpp (original)<br>
+++ cfe/trunk/test/Misc/diag-aka-types.cpp Tue Jun 26 13:18:47 2012<br>
@@ -30,27 +30,6 @@<br>
bar::f(x); // expected-error{{cannot initialize a parameter of type 'Foo::foo *' (aka 'bar::Foo::foo *') with an lvalue of type 'Foo::foo *'}}<br>
}<br>
<br>
-// PR9548 - "no known conversion from 'vector<string>' to 'vector<string>'"<br>
-// vector<string> refers to two different types here. Make sure the message<br>
-// gives a way to tell them apart.<br>
-class versa_string;<br>
-typedef versa_string string;<br>
-<br>
-namespace std {template <typename T> class vector;}<br>
-using std::vector;<br>
-<br>
-void f(vector<string> v); // expected-note {{candidate function not viable: no known conversion from 'vector<string>' (aka 'std::vector<std::basic_string>') to 'vector<string>' (aka 'std::vector<versa_string>') for 1st argument}}<br>
-<br>
-namespace std {<br>
- class basic_string;<br>
- typedef basic_string string;<br>
- template <typename T> class vector {};<br>
- void g() {<br>
- vector<string> v;<br>
- f(v); // expected-error{{no matching function for call to 'f'}}<br>
- }<br>
-}<br>
-<br>
namespace ns {<br>
struct str {<br>
static void method(struct data *) {}<br>
<br>
Added: cfe/trunk/test/Misc/diag-template-diffing.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/diag-template-diffing.cpp?rev=159216&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/diag-template-diffing.cpp?rev=159216&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Misc/diag-template-diffing.cpp (added)<br>
+++ cfe/trunk/test/Misc/diag-template-diffing.cpp Tue Jun 26 13:18:47 2012<br>
@@ -0,0 +1,433 @@<br>
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-ELIDE-NOTREE<br>
+// RUN: %clang_cc1 -fsyntax-only %s -fno-elide-type -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-NOELIDE-NOTREE<br>
+// RUN: %clang_cc1 -fsyntax-only %s -fdiagnostics-show-template-tree -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-ELIDE-TREE<br>
+// RUN: %clang_cc1 -fsyntax-only %s -fno-elide-type -fdiagnostics-show-template-tree -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-NOELIDE-TREE<br>
+<br>
+// PR9548 - "no known conversion from 'vector<string>' to 'vector<string>'"<br>
+// vector<string> refers to two different types here. Make sure the message<br>
+// gives a way to tell them apart.<br>
+class versa_string;<br>
+typedef versa_string string;<br>
+<br>
+namespace std {template <typename T> class vector;}<br>
+using std::vector;<br>
+<br>
+void f(vector<string> v);<br>
+<br>
+namespace std {<br>
+ class basic_string;<br>
+ typedef basic_string string;<br>
+ template <typename T> class vector {};<br>
+ void g() {<br>
+ vector<string> v;<br>
+ f(v);<br>
+ }<br>
+} // end namespace std<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<class std::basic_string>' to 'vector<class versa_string>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<class std::basic_string>' to 'vector<class versa_string>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'f'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-ELIDE-TREE: vector<<br>
+// CHECK-ELIDE-TREE: [class std::basic_string != class versa_string]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-NOELIDE-TREE: vector<<br>
+// CHECK-NOELIDE-TREE: [class std::basic_string != class versa_string]><br>
+<br>
+template <int... A><br>
+class I1{};<br>
+void set1(I1<1,2,3,4,2,3,4,3>) {};<br>
+void test1() {<br>
+ set1(I1<1,2,3,4,2,2,4,3,7>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set1'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'I1<[5 * ...], 2, [2 * ...], 7>' to 'I1<[5 * ...], 3, [2 * ...], (no argument)>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set1'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'I1<1, 2, 3, 4, 2, 2, 4, 3, 7>' to 'I1<1, 2, 3, 4, 2, 3, 4, 3, (no argument)>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set1'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-ELIDE-TREE: I1<<br>
+// CHECK-ELIDE-TREE: [5 * ...],<br>
+// CHECK-ELIDE-TREE: [2 != 3],<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: [7 != (no argument)]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set1'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-NOELIDE-TREE: I1<<br>
+// CHECK-NOELIDE-TREE: 1,<br>
+// CHECK-NOELIDE-TREE: 2,<br>
+// CHECK-NOELIDE-TREE: 3,<br>
+// CHECK-NOELIDE-TREE: 4,<br>
+// CHECK-NOELIDE-TREE: 2,<br>
+// CHECK-NOELIDE-TREE: [2 != 3],<br>
+// CHECK-NOELIDE-TREE: 4,<br>
+// CHECK-NOELIDE-TREE: 3,<br>
+// CHECK-NOELIDE-TREE: [7 != (no argument)]><br>
+<br>
+template <class A, class B, class C = void><br>
+class I2{};<br>
+void set2(I2<int, int>) {};<br>
+void test2() {<br>
+ set2(I2<double, int, int>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set2'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'I2<double, [...], int>' to 'I2<int, [...], (default) void>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set2'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'I2<double, int, int>' to 'I2<int, int, (default) void>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set2'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-ELIDE-TREE: I2<<br>
+// CHECK-ELIDE-TREE: [double != int],<br>
+// CHECK-ELIDE-TREE: [...],<br>
+// CHECK-ELIDE-TREE: [int != (default) void]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set2'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-NOELIDE-TREE: I2<<br>
+// CHECK-NOELIDE-TREE: [double != int],<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: [int != (default) void]><br>
+<br>
+int V1, V2, V3;<br>
+template <int* A, int *B><br>
+class I3{};<br>
+void set3(I3<&V1, &V2>) {};<br>
+void test3() {<br>
+ set3(I3<&V3, &V2>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set3'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'I3<&V3, [...]>' to 'I3<&V1, [...]>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set3'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'I3<&V3, &V2>' to 'I3<&V1, &V2>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set3'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-ELIDE-TREE: I3<<br>
+// CHECK-ELIDE-TREE: [&V3 != &V1]<br>
+// CHECK-ELIDE-TREE: [...]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set3'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-NOELIDE-TREE: I3<<br>
+// CHECK-NOELIDE-TREE: [&V3 != &V1]<br>
+// CHECK-NOELIDE-TREE: &V2><br>
+<br>
+template <class A, class B><br>
+class Alpha{};<br>
+template <class A, class B><br>
+class Beta{};<br>
+template <class A, class B><br>
+class Gamma{};<br>
+template <class A, class B><br>
+class Delta{};<br>
+<br>
+void set4(Alpha<int, int>);<br>
+void test4() {<br>
+ set4(Beta<void, void>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set4'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'Beta<void, void>' to 'Alpha<int, int>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set4'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'Beta<void, void>' to 'Alpha<int, int>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set4'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from 'Beta<void, void>' to 'Alpha<int, int>' for 1st argument<br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set4'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from 'Beta<void, void>' to 'Alpha<int, int>' for 1st argument<br>
+<br>
+void set5(Alpha<Beta<Gamma<Delta<int, int>, int>, int>, int>);<br>
+void test5() {<br>
+ set5(Alpha<Beta<Gamma<void, void>, double>, double>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set5'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'Alpha<Beta<Gamma<void, void>, double>, double>' to 'Alpha<Beta<Gamma<Delta<int, int>, int>, int>, int>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set5'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'Alpha<Beta<Gamma<void, void>, double>, double>' to 'Alpha<Beta<Gamma<Delta<int, int>, int>, int>, int>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set5'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-ELIDE-TREE: Alpha<<br>
+// CHECK-ELIDE-TREE: Beta<<br>
+// CHECK-ELIDE-TREE: Gamma<<br>
+// CHECK-ELIDE-TREE: [void != Delta<int, int>],<br>
+// CHECK-ELIDE-TREE: [void != int]><br>
+// CHECK-ELIDE-TREE: [double != int]><br>
+// CHECK-ELIDE-TREE: [double != int]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set5'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-NOELIDE-TREE: Alpha<<br>
+// CHECK-NOELIDE-TREE: Beta<<br>
+// CHECK-NOELIDE-TREE: Gamma<<br>
+// CHECK-NOELIDE-TREE: [void != Delta<int, int>],<br>
+// CHECK-NOELIDE-TREE: [void != int]><br>
+// CHECK-NOELIDE-TREE: [double != int]><br>
+// CHECK-NOELIDE-TREE: [double != int]><br>
+<br>
+void test6() {<br>
+ set5(Alpha<Beta<Delta<int, int>, int>, int>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set5'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'Alpha<Beta<Delta<int, int>, [...]>, [...]>' to 'Alpha<Beta<Gamma<Delta<int, int>, int>, [...]>, [...]>' for 1st argument<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set5'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'Alpha<Beta<Delta<int, int>, int>, int>' to 'Alpha<Beta<Gamma<Delta<int, int>, int>, int>, int>' for 1st argument<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set5'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-ELIDE-TREE: Alpha<<br>
+// CHECK-ELIDE-TREE: Beta<<br>
+// CHECK-ELIDE-TREE: [Delta<int, int> != Gamma<Delta<int, int>, int>],<br>
+// CHECK-ELIDE-TREE: [...]><br>
+// CHECK-ELIDE-TREE: [...]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set5'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument<br>
+// CHECK-NOELIDE-TREE: Alpha<<br>
+// CHECK-NOELIDE-TREE: Beta<<br>
+// CHECK-NOELIDE-TREE: [Delta<int, int> != Gamma<Delta<int, int>, int>],<br>
+// CHECK-NOELIDE-TREE: int><br>
+// CHECK-NOELIDE-TREE: int><br>
+<br>
+int a7, b7;<br>
+int c7[] = {1,2,3};<br>
+template<int *A><br>
+class class7 {};<br>
+void set7(class7<&a7> A) {}<br>
+void test7() {<br>
+ set7(class7<&a7>());<br>
+ set7(class7<&b7>());<br>
+ set7(class7<c7>());<br>
+ set7(class7<nullptr>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set7'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class7<&b7>' to 'class7<&a7>' for 1st argument;<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set7'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class7<c7>' to 'class7<&a7>' for 1st argument;<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set7'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class7<nullptr>' to 'class7<&a7>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set7'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class7<&b7>' to 'class7<&a7>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set7'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class7<c7>' to 'class7<&a7>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set7'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class7<nullptr>' to 'class7<&a7>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set7'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class7<<br>
+// CHECK-ELIDE-TREE: [&b7 != &a7]><br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set7'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class7<<br>
+// CHECK-ELIDE-TREE: [c7 != &a7]><br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set7'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class7<<br>
+// CHECK-ELIDE-TREE: [nullptr != &a7]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set7'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class7<<br>
+// CHECK-NOELIDE-TREE: [&b7 != &a7]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set7'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class7<<br>
+// CHECK-NOELIDE-TREE: [c7 != &a7]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set7'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class7<<br>
+// CHECK-NOELIDE-TREE: [nullptr != &a7]><br>
+<br>
+template<typename ...T> struct S8 {};<br>
+template<typename T> using U8 = S8<int, char, T>;<br>
+int f8(S8<int, char, double>);<br>
+int k8 = f8(U8<char>());<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f8'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S8<[2 * ...], char>' to 'S8<[2 * ...], double>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f8'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S8<int, char, char>' to 'S8<int, char, double>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'f8'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: S8<<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: [char != double]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f8'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: S8<<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: char,<br>
+// CHECK-NOELIDE-TREE: [char != double]><br>
+<br>
+template<typename ...T> struct S9 {};<br>
+template<typename T> using U9 = S9<int, char, T>;<br>
+template<typename T> using V9 = U9<U9<T>>;<br>
+int f9(S9<int, char, U9<const double>>);<br>
+int k9 = f9(V9<double>());<br>
+<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f9'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], S9<[2 * ...], double>>' to 'S9<[2 * ...], S9<[2 * ...], const double>>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f9'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<int, char, S9<int, char, double>>' to 'S9<int, char, S9<int, char, const double>>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'f9'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: S9<<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: S9<<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: [double != const double]>><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f9'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: S9<<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: char,<br>
+// CHECK-NOELIDE-TREE: S9<<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: char,<br>
+// CHECK-NOELIDE-TREE: [double != const double]>><br>
+<br>
+template<typename ...A> class class_types {};<br>
+void set10(class_types<int, int>) {}<br>
+void test10() {<br>
+ set10(class_types<int>());<br>
+ set10(class_types<int, int, int>());<br>
+}<br>
+<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set10'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_types<[...], (no argument)>' to 'class_types<[...], int>' for 1st argument;<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set10'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_types<[2 * ...], int>' to 'class_types<[2 * ...], (no argument)>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set10'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_types<int, (no argument)>' to 'class_types<int, int>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set10'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_types<int, int, int>' to 'class_types<int, int, (no argument)>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set10'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_types<<br>
+// CHECK-ELIDE-TREE: [...],<br>
+// CHECK-ELIDE-TREE: [(no argument) != int]><br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set10'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_types<<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: [int != (no argument)]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set10'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_types<<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: [(no argument) != int]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set10'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_types<<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: int,<br>
+// CHECK-NOELIDE-TREE: [int != (no argument)]><br>
+<br>
+template<int ...A> class class_ints {};<br>
+void set11(class_ints<2, 3>) {}<br>
+void test11() {<br>
+ set11(class_ints<1>());<br>
+ set11(class_ints<0, 3, 6>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set11'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ints<1, (no argument)>' to 'class_ints<2, 3>' for 1st argument;<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set11'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ints<0, [...], 6>' to 'class_ints<2, [...], (no argument)>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set11'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ints<1, (no argument)>' to 'class_ints<2, 3>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set11'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ints<0, 3, 6>' to 'class_ints<2, 3, (no argument)>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set11'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_ints<<br>
+// CHECK-ELIDE-TREE: [1 != 2],<br>
+// CHECK-ELIDE-TREE: [(no argument) != 3]><br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set11'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_ints<<br>
+// CHECK-ELIDE-TREE: [0 != 2],<br>
+// CHECK-ELIDE-TREE: [...],<br>
+// CHECK-ELIDE-TREE: [6 != (no argument)]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set11'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_ints<<br>
+// CHECK-NOELIDE-TREE: [1 != 2],<br>
+// CHECK-NOELIDE-TREE: [(no argument) != 3]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set11'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_ints<<br>
+// CHECK-NOELIDE-TREE: [0 != 2],<br>
+// CHECK-NOELIDE-TREE: 3,<br>
+// CHECK-NOELIDE-TREE: [6 != (no argument)]><br>
+<br>
+template<template<class> class ...A> class class_template_templates {};<br>
+template<class> class tt1 {};<br>
+template<class> class tt2 {};<br>
+void set12(class_template_templates<tt1, tt1>) {}<br>
+void test12() {<br>
+ set12(class_template_templates<tt2>());<br>
+ set12(class_template_templates<tt1, tt1, tt1>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set12'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_template_templates<template tt2, template (no argument)>' to 'class_template_templates<template tt1, template tt1>' for 1st argument;<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set12'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_template_templates<[2 * ...], template tt1>' to 'class_template_templates<[2 * ...], template (no argument)>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set12'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_template_templates<template tt2, template (no argument)>' to 'class_template_templates<template tt1, template tt1>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set12'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_template_templates<template tt1, template tt1, template tt1>' to 'class_template_templates<template tt1, template tt1, template (no argument)>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set12'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_template_templates<<br>
+// CHECK-ELIDE-TREE: [template tt2 != template tt1],<br>
+// CHECK-ELIDE-TREE: [template (no argument) != template tt1]><br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set12'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_template_templates<<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: [template tt1 != template (no argument)]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set12'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_template_templates<<br>
+// CHECK-NOELIDE-TREE: [template tt2 != template tt1],<br>
+// CHECK-NOELIDE-TREE: [template (no argument) != template tt1]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set12'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_template_templates<<br>
+// CHECK-NOELIDE-TREE: template tt1,<br>
+// CHECK-NOELIDE-TREE: template tt1,<br>
+// CHECK-NOELIDE-TREE: [template tt1 != template (no argument)]><br>
+<br>
+double a13, b13, c13, d13;<br>
+template<double* ...A> class class_ptrs {};<br>
+void set13(class_ptrs<&a13, &b13>) {}<br>
+void test13() {<br>
+ set13(class_ptrs<&c13>());<br>
+ set13(class_ptrss<&a13, &b13, &d13>());<br>
+}<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set13'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ptrs<&c13, (no argument)>' to 'class_ptrs<&a13, &b13>' for 1st argument;<br>
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set13'<br>
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ptrs<[2 * ...], &d13>' to 'class_ptrs<[2 * ...], (no argument)>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set13'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ptrs<&c13, (no argument)>' to 'class_ptrs<&a13, &b13>' for 1st argument;<br>
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set13'<br>
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ptrs<&a13, &b13, &d13>' to 'class_ptrs<&a13, &b13, (no argument)>' for 1st argument;<br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set13'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_ptrs<<br>
+// CHECK-ELIDE-TREE: [&c13 != &a13],<br>
+// CHECK-ELIDE-TREE: [(no argument) != &b13]><br>
+// CHECK-ELIDE-TREE: no matching function for call to 'set13'<br>
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-ELIDE-TREE: class_ptrs<<br>
+// CHECK-ELIDE-TREE: [2 * ...],<br>
+// CHECK-ELIDE-TREE: [&d13 != (no argument)]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set13'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_ptrs<<br>
+// CHECK-NOELIDE-TREE: [&c13 != &a13],<br>
+// CHECK-NOELIDE-TREE: [(no argument) != &b13]><br>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set13'<br>
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion for 1st argument;<br>
+// CHECK-NOELIDE-TREE: class_ptrs<<br>
+// CHECK-NOELIDE-TREE: &a13,<br>
+// CHECK-NOELIDE-TREE: &b13,<br>
+// CHECK-NOELIDE-TREE: [&d13 != (no argument)]><br>
+<br>
+<br>
+// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.<br>
+// CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.<br>
+// CHECK-ELIDE-TREE: {{[0-9]*}} errors generated.<br>
+// CHECK-NOELIDE-TREE: {{[0-9]*}} errors generated.<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></font></div>