Add new diff modes to template type diffing.

Remove an old assertion that does not hold.  It is possible for a template
argument to be a declaration in one instantiation and an integer in another.
Create two new diff kinds for these (decl vs int and int vs decl).

llvm-svn: 257869
This commit is contained in:
Richard Trieu 2016-01-15 05:01:53 +00:00
parent 2c485a7003
commit 9213ce559a
3 changed files with 272 additions and 11 deletions

View File

@ -511,7 +511,10 @@ class TemplateDiff {
/// Integer difference
Integer,
/// Declaration difference, nullptr arguments are included here
Declaration
Declaration,
/// One argument being integer and the other being declaration
FromIntegerAndToDeclaration,
FromDeclarationAndToInteger
};
private:
@ -648,6 +651,40 @@ class TemplateDiff {
SetDefault(FromDefault, ToDefault);
}
void SetFromDeclarationAndToIntegerDiff(
ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr,
Expr *FromExpr, llvm::APSInt ToInt, bool IsValidToInt,
QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) {
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger;
FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
SetDefault(FromDefault, ToDefault);
}
void SetFromIntegerAndToDeclarationDiff(
llvm::APSInt FromInt, bool IsValidFromInt, QualType FromIntType,
Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf,
bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) {
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration;
FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
SetDefault(FromDefault, ToDefault);
}
/// SetDefault - Sets FromDefault and ToDefault flags of the current node.
void SetDefault(bool FromDefault, bool ToDefault) {
assert(!FromDefault || !ToDefault && "Both arguments cannot be default.");
@ -761,6 +798,38 @@ class TemplateDiff {
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
}
void GetFromDeclarationAndToIntegerDiff(
ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr,
Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt,
QualType &ToIntType, Expr *&ToExpr) {
assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger &&
"Unexpected kind.");
FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
ToInt = FlatTree[ReadNode].ToArgInfo.Val;
IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
}
void GetFromIntegerAndToDeclarationDiff(
llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType,
Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf,
bool &ToNullPtr, Expr *&ToExpr) {
assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration &&
"Unexpected kind.");
FromInt = FlatTree[ReadNode].FromArgInfo.Val;
IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
}
/// FromDefault - Return true if the from argument is the default.
bool FromDefault() {
return FlatTree[ReadNode].FromArgInfo.IsDefault;
@ -1139,18 +1208,31 @@ class TemplateDiff {
HasToInt, ToIntType, ToNullPtr, ToExpr,
ToValueDecl, NeedToAddressOf);
bool FromDeclaration = FromValueDecl || FromNullPtr;
bool ToDeclaration = ToValueDecl || ToNullPtr;
assert(((!HasFromInt && !HasToInt) ||
(!FromDeclaration && !ToDeclaration)) &&
"Template argument cannot be both integer and declaration");
bool FromDefault = FromIter.isEnd() &&
(FromExpr || FromValueDecl || HasFromInt || FromNullPtr);
bool ToDefault = ToIter.isEnd() &&
(ToExpr || ToValueDecl || HasToInt || ToNullPtr);
bool FromDeclaration = FromValueDecl || FromNullPtr;
bool ToDeclaration = ToValueDecl || ToNullPtr;
if (FromDeclaration && HasToInt) {
Tree.SetFromDeclarationAndToIntegerDiff(
FromValueDecl, NeedFromAddressOf, FromNullPtr, FromExpr, ToInt,
HasToInt, ToIntType, ToExpr, FromDefault, ToDefault);
Tree.SetSame(false);
return;
}
if (HasFromInt && ToDeclaration) {
Tree.SetFromIntegerAndToDeclarationDiff(
FromInt, HasFromInt, FromIntType, FromExpr, ToValueDecl,
NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault);
Tree.SetSame(false);
return;
}
if (HasFromInt || HasToInt) {
Tree.SetIntegerDiff(FromInt, ToInt, HasFromInt, HasToInt, FromIntType,
ToIntType, FromExpr, ToExpr, FromDefault, ToDefault);
@ -1383,6 +1465,42 @@ class TemplateDiff {
Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::FromDeclarationAndToInteger: {
ValueDecl *FromValueDecl;
bool FromAddressOf;
bool FromNullPtr;
Expr *FromExpr;
llvm::APSInt ToInt;
bool IsValidToInt;
QualType ToIntType;
Expr *ToExpr;
Tree.GetFromDeclarationAndToIntegerDiff(
FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt,
IsValidToInt, ToIntType, ToExpr);
assert((FromValueDecl || FromNullPtr) && IsValidToInt);
PrintValueDeclAndInteger(FromValueDecl, FromAddressOf, FromNullPtr,
FromExpr, Tree.FromDefault(), ToInt, ToIntType,
ToExpr, Tree.ToDefault());
return;
}
case DiffTree::FromIntegerAndToDeclaration: {
llvm::APSInt FromInt;
bool IsValidFromInt;
QualType FromIntType;
Expr *FromExpr;
ValueDecl *ToValueDecl;
bool ToAddressOf;
bool ToNullPtr;
Expr *ToExpr;
Tree.GetFromIntegerAndToDeclarationDiff(
FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl,
ToAddressOf, ToNullPtr, ToExpr);
assert(IsValidFromInt && (ToValueDecl || ToNullPtr));
PrintIntegerAndValueDecl(FromInt, FromIntType, FromExpr,
Tree.FromDefault(), ToValueDecl, ToAddressOf,
ToNullPtr, ToExpr, Tree.ToDefault());
return;
}
case DiffTree::Template: {
// Node is root of template. Recurse on children.
TemplateDecl *FromTD, *ToTD;
@ -1715,6 +1833,48 @@ class TemplateDiff {
}
/// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and
/// APSInt to print a mixed difference.
void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf,
bool IsNullPtr, Expr *VDExpr, bool DefaultDecl,
llvm::APSInt Val, QualType IntType,
Expr *IntExpr, bool DefaultInt) {
if (!PrintTree) {
OS << (DefaultDecl ? "(default) " : "");
Bold();
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
Unbold();
} else {
OS << (DefaultDecl ? "[(default) " : "[");
Bold();
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
Unbold();
OS << " != " << (DefaultInt ? "(default) " : "");
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
OS << ']';
}
}
/// PrintIntegerAndValueDecl - Uses the print functions for APSInt and
/// ValueDecl to print a mixed difference.
void PrintIntegerAndValueDecl(llvm::APSInt Val, QualType IntType,
Expr *IntExpr, bool DefaultInt, ValueDecl *VD,
bool NeedAddressOf, bool IsNullPtr,
Expr *VDExpr, bool DefaultDecl) {
if (!PrintTree) {
OS << (DefaultInt ? "(default) " : "");
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
} else {
OS << (DefaultInt ? "[(default) " : "[");
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
OS << " != " << (DefaultDecl ? "(default) " : "");
Bold();
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
Unbold();
OS << ']';
}
}
// Prints the appropriate placeholder for elided template arguments.
void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) {
if (PrintTree) {

View File

@ -1,5 +1,5 @@
// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics %s 2>&1 | FileCheck %s
// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics %s 2>&1 | FileCheck %s
// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
// REQUIRES: ansi-escape-sequences
template<typename> struct foo {};
void func(foo<int>);
@ -82,5 +82,23 @@ namespace default_args {
// CHECK: no viable conversion from 'A<[2 * ...], (default) [[CYAN]]2[[RESET]][[BOLD]]>' to 'A<[2 * ...], [[CYAN]]0[[RESET]][[BOLD]]>'
A<0, 2, 0> N2 = M;
}
}
namespace MixedDeclarationIntegerArgument {
template<typename T, T n = 5> class A{};
int x;
int y[5];
A<int> a1 = A<int&, x>();
// CHECK: no viable conversion from 'A<[[CYAN]]int &[[RESET]][[BOLD]], [[CYAN]]x[[RESET]][[BOLD]]>' to 'A<[[CYAN]]int[[RESET]][[BOLD]], (default) [[CYAN]]5[[RESET]][[BOLD]]>'
// TREE: no viable conversion
// TREE: A<
// TREE: {{\[}}[[CYAN]]int &[[RESET]][[BOLD]] != [[CYAN]]int[[RESET]][[BOLD]]],
// TREE: {{\[}}[[CYAN]]x[[RESET]][[BOLD]] != (default) [[CYAN]]5[[RESET]][[BOLD]]]>
A<int**, nullptr> a2 = A<int, 3 + 1>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<[[CYAN]]int[[RESET]][[BOLD]], [[CYAN]]3 + 1[[RESET]][[BOLD]] aka [[CYAN]]4[[RESET]][[BOLD]]>' to 'A<[[CYAN]]int **[[RESET]][[BOLD]], [[CYAN]]nullptr[[RESET]][[BOLD]]>'
// TREE: no viable conversion
// TREE: A<
// TREE: {{\[}}[[CYAN]]int[[RESET]][[BOLD]] != [[CYAN]]int **[[RESET]][[BOLD]]],
// TREE: {{\[}}[[CYAN]]3 + 1[[RESET]][[BOLD]] aka [[CYAN]]4[[RESET]][[BOLD]] != [[CYAN]]nullptr[[RESET]][[BOLD]]]>
}

View File

@ -1287,6 +1287,89 @@ void foo() {
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<signed char, (signed char) 1>' to 'A<bool, (bool) true>'
}
namespace MixedDeclarationIntegerArgument {
template<typename T, T n> class A{};
int x;
int y[5];
A<int, 5> a1 = A<int&, x>();
A<int, 5 - 1> a2 = A<int*, &x>();
A<int, 5 + 1> a3 = A<int*, y>();
A<int, 0> a4 = A<int**, nullptr>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int &, x>' to 'A<int, 5>'
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int *, &x>' to 'A<int, 5 - 1 aka 4>'
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int *, y>' to 'A<int, 5 + 1 aka 6>'
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int **, nullptr>' to 'A<int, 0>'
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int & != int],
// CHECK-ELIDE-TREE: [x != 5]>
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int * != int],
// CHECK-ELIDE-TREE: [&x != 5 - 1 aka 4]>
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int * != int],
// CHECK-ELIDE-TREE: [y != 5 + 1 aka 6]>
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int ** != int],
// CHECK-ELIDE-TREE: [nullptr != 0]>
A<int&, x> a5 = A<int, 3>();
A<int*, &x> a6 = A<int, 3 - 1>();
A<int*, y> a7 = A<int, 3 + 1>();
A<int**, nullptr> a8 = A<int, 3>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3>' to 'A<int &, x>'
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3 - 1 aka 2>' to 'A<int *, &x>'
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3 + 1 aka 4>' to 'A<int *, y>'
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3>' to 'A<int **, nullptr>'
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int != int &],
// CHECK-ELIDE-TREE: [3 != x]>
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int != int *],
// CHECK-ELIDE-TREE: [3 - 1 aka 2 != &x]>
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int != int *],
// CHECK-ELIDE-TREE: [3 + 1 aka 4 != y]>
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: A<
// CHECK-ELIDE-TREE: [int != int **],
// CHECK-ELIDE-TREE: [3 != nullptr]>
template<class T, T n = x> class B{} ;
B<int, 5> b1 = B<int&>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int &, (default) x>' to 'B<int, 5>'
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: B<
// CHECK-ELIDE-TREE: [int & != int],
// CHECK-ELIDE-TREE: [(default) x != 5]>
B<int &> b2 = B<int, 2>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int, 2>' to 'B<int &, (default) x>'
// CHECK-ELIDE-TREE: B<
// CHECK-ELIDE-TREE: [int != int &],
// CHECK-ELIDE-TREE: [2 != (default) x]>
template<class T, T n = 11> class C {};
C<int> c1 = C<int&, x>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C<int &, x>' to 'C<int, (default) 11>'
// CHECK-ELIDE-TREE: error: no viable conversion
// CHECK-ELIDE-TREE: C<
// CHECK-ELIDE-TREE: [int & != int],
// CHECK-ELIDE-TREE: [x != (default) 11]>
C<int &, x> c2 = C<int>();
// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C<int, (default) 11>' to 'C<int &, x>'
// CHECK-ELIDE-TREE: C<
// CHECK-ELIDE-TREE: [int != int &],
// CHECK-ELIDE-TREE: [(default) 11 != x]>
}
// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
// CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.