Fixing more issues with template type diffing
authorRichard Trieu <rtrieu@google.com>
Fri, 15 Jan 2016 05:48:38 +0000 (05:48 +0000)
committerRichard Trieu <rtrieu@google.com>
Fri, 15 Jan 2016 05:48:38 +0000 (05:48 +0000)
1) Print qualifiers for templates with zero arguments
2) Add a few more tests for the template type diffing refactoring.
Specifically, PR24587 has been fixed and has a test case from
http://reviews.llvm.org/D15384
3) Adds asserts to check the DiffTree is in correct state when moving nodes
4) Rename the field FromType and ToType since it is heavily used within
member functions.

llvm-svn: 257870

clang/lib/AST/ASTDiagnostic.cpp
clang/test/Misc/diag-template-diffing.cpp

index 12774c6..cff9251 100644 (file)
@@ -473,14 +473,14 @@ class TemplateDiff {
   /// ShowColor - Diagnostics support color, so bolding will be used.
   bool ShowColor;
 
-  /// FromType - When single type printing is selected, this is the type to be
-  /// be printed.  When tree printing is selected, this type will show up first
-  /// in the tree.
-  QualType FromType;
+  /// FromTemplateType - When single type printing is selected, this is the
+  /// type to be be printed.  When tree printing is selected, this type will
+  /// show up first in the tree.
+  QualType FromTemplateType;
 
-  /// ToType - The type that FromType is compared to.  Only in tree printing
-  /// will this type be outputed.
-  QualType ToType;
+  /// ToTemplateType - The type that FromType is compared to.  Only in tree
+  /// printing will this type be outputed.
+  QualType ToTemplateType;
 
   /// OS - The stream used to construct the output strings.
   raw_ostream &OS;
@@ -704,12 +704,16 @@ class TemplateDiff {
 
     /// Up - Changes the node to the parent of the current node.
     void Up() {
+      assert(FlatTree[CurrentNode].Kind != Invalid &&
+             "Cannot exit node before setting node information.");
       CurrentNode = FlatTree[CurrentNode].ParentNode;
     }
 
     /// AddNode - Adds a child node to the current node, then sets that node
     /// node as the current node.
     void AddNode() {
+      assert(FlatTree[CurrentNode].Kind == Template &&
+             "Only Template nodes can have children nodes.");
       FlatTree.push_back(DiffNode(CurrentNode));
       DiffNode &Node = FlatTree[CurrentNode];
       if (Node.ChildNode == 0) {
@@ -1032,7 +1036,7 @@ class TemplateDiff {
   // These functions build up the template diff tree, including functions to
   // retrieve and compare template arguments.
 
-  static const TemplateSpecializationType * GetTemplateSpecializationType(
+  static const TemplateSpecializationType *GetTemplateSpecializationType(
       ASTContext &Context, QualType Ty) {
     if (const TemplateSpecializationType *TST =
             Ty->getAs<TemplateSpecializationType>())
@@ -1507,6 +1511,8 @@ class TemplateDiff {
         Qualifiers FromQual, ToQual;
         Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual);
 
+        PrintQualifiers(FromQual, ToQual);
+
         if (!Tree.HasChildren()) {
           // If we're dealing with a template specialization with zero
           // arguments, there are no children; special-case this.
@@ -1514,8 +1520,6 @@ class TemplateDiff {
           return;
         }
 
-        PrintQualifiers(FromQual, ToQual);
-
         OS << FromTD->getNameAsString() << '<';
         Tree.MoveToChild();
         unsigned NumElideArgs = 0;
@@ -1962,21 +1966,21 @@ public:
       PrintTree(PrintTree),
       ShowColor(ShowColor),
       // When printing a single type, the FromType is the one printed.
-      FromType(PrintFromType ? FromType : ToType),
-      ToType(PrintFromType ? ToType : FromType),
+      FromTemplateType(PrintFromType ? FromType : ToType),
+      ToTemplateType(PrintFromType ? ToType : FromType),
       OS(OS),
       IsBold(false) {
   }
 
   /// DiffTemplate - Start the template type diffing.
   void DiffTemplate() {
-    Qualifiers FromQual = FromType.getQualifiers(),
-               ToQual = ToType.getQualifiers();
+    Qualifiers FromQual = FromTemplateType.getQualifiers(),
+               ToQual = ToTemplateType.getQualifiers();
 
     const TemplateSpecializationType *FromOrigTST =
-        GetTemplateSpecializationType(Context, FromType);
+        GetTemplateSpecializationType(Context, FromTemplateType);
     const TemplateSpecializationType *ToOrigTST =
-        GetTemplateSpecializationType(Context, ToType);
+        GetTemplateSpecializationType(Context, ToTemplateType);
 
     // Only checking templates.
     if (!FromOrigTST || !ToOrigTST)
index cf850a5..70d5e7c 100644 (file)
@@ -1371,6 +1371,62 @@ C<int &, x> c2 = C<int>();
 // CHECK-ELIDE-TREE:     [(default) 11 != x]>
 }
 
+namespace default_args {
+  template <int x, int y = 1+1, int z = 2>
+  class A {};
+
+  void foo(A<0> &M) {
+    // CHECK-ELIDE-NOTREE: no viable conversion from 'A<[...], (default) 1 + 1 aka 2, (default) 2>' to 'A<[...], 0, 0>'
+    A<0, 0, 0> N = M;
+
+    // CHECK-ELIDE-NOTREE: no viable conversion from 'A<[2 * ...], (default) 2>' to 'A<[2 * ...], 0>'
+    A<0, 2, 0> N2 = M;
+  }
+}
+
+namespace DefaultNonTypeArgWithDependentType {
+// We used to crash diffing integer template arguments when the argument type
+// is dependent and default arguments were used.
+template <typename SizeType = int, SizeType = 0> struct A {};
+template <typename R = A<>> R bar();
+A<> &foo() { return bar(); }
+// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<[2 * ...]>' cannot bind to a temporary of type 'A<[2 * ...]>'
+// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<int, 0>' cannot bind to a temporary of type 'A<int, 0>'
+}
+
+namespace PR24587 {
+template <typename T, T v>
+struct integral_constant {};
+
+auto false_ = integral_constant<bool, false> {};
+
+template <typename T>
+void f(T, decltype(false_));
+
+void run() {
+  f(1, integral_constant<bool, true>{});
+}
+// CHECK-ELIDE-NOTREE: error: no matching function for call to 'f'
+// CHECK-ELIDE-NOTREE: note: candidate function [with T = int] not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
+}
+
+namespace ZeroArgs {
+template <int N = 0> class A {};
+template <class T = A<>> class B {};
+A<1> a1 = A<>();
+A<> a2 = A<1>();
+B<> b1 = B<int>();
+B<int> b2 = B<>();
+B<> b3 = B<const A<>>();
+B<const A<>> b4 = B<>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<(default) 0>' to 'A<1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<1>' to 'A<(default) 0>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int>' to 'B<(default) ZeroArgs::A<0>>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<(default) ZeroArgs::A<0>>' to 'B<int>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<const A<[...]>>' to 'B<A<[...]>>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<A<[...]>>' to 'B<const A<[...]>>'
+}
+
 // CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
 // CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.
 // CHECK-ELIDE-TREE: {{[0-9]*}} errors generated.