From 3880089fc7e7b4c2be8eccb09379a02db9160189 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Thu, 24 Jul 2014 04:24:50 +0000 Subject: [PATCH] Add support for nullptr template arguments to template type diffing. llvm-svn: 213840 --- clang/lib/AST/ASTDiagnostic.cpp | 138 +++++++++++++++++----- clang/test/Misc/diag-template-diffing.cpp | 54 +++++++++ 2 files changed, 161 insertions(+), 31 deletions(-) diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 5f78df2c473b..5e6acf8e97de 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -472,6 +472,9 @@ class TemplateDiff { /// FromExpr, ToExpr - The expression arguments. Expr *FromExpr, *ToExpr; + /// FromNullPtr, ToNullPtr - If the template argument is a nullptr + bool FromNullPtr, ToNullPtr; + /// FromTD, ToTD - The template decl for template template /// arguments or the type arguments that are templates. TemplateDecl *FromTD, *ToTD; @@ -501,6 +504,7 @@ class TemplateDiff { DiffNode(unsigned ParentNode = 0) : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode), FromType(), ToType(), FromExpr(nullptr), ToExpr(nullptr), + FromNullPtr(false), ToNullPtr(false), FromTD(nullptr), ToTD(nullptr), IsValidFromInt(false), IsValidToInt(false), FromValueDecl(nullptr), ToValueDecl(nullptr), FromAddressOf(false), ToAddressOf(false), FromDefault(false), @@ -574,6 +578,12 @@ class TemplateDiff { FlatTree[CurrentNode].Same = Same; } + /// SetNullPtr - Sets the NullPtr flags of the current node. + void SetNullPtr(bool FromNullPtr, bool ToNullPtr) { + FlatTree[CurrentNode].FromNullPtr = FromNullPtr; + FlatTree[CurrentNode].ToNullPtr = ToNullPtr; + } + /// SetDefault - Sets FromDefault and ToDefault flags of the current node. void SetDefault(bool FromDefault, bool ToDefault) { FlatTree[CurrentNode].FromDefault = FromDefault; @@ -696,6 +706,16 @@ class TemplateDiff { return FlatTree[ReadNode].NextNode != 0; } + /// FromNullPtr - Returns true if the from argument is null. + bool FromNullPtr() { + return FlatTree[ReadNode].FromNullPtr; + } + + /// ToNullPtr - Returns true if the to argument is null. + bool ToNullPtr() { + return FlatTree[ReadNode].ToNullPtr; + } + /// FromDefault - Return true if the from argument is the default. bool FromDefault() { return FlatTree[ReadNode].FromDefault; @@ -934,6 +954,10 @@ class TemplateDiff { bool HasToValueDecl = !ToIter.isEnd() && ToIter->getKind() == TemplateArgument::Declaration; + bool FromNullPtr = !FromIter.isEnd() && + FromIter->getKind() == TemplateArgument::NullPtr; + bool ToNullPtr = + !ToIter.isEnd() && ToIter->getKind() == TemplateArgument::NullPtr; assert(((!HasFromInt && !HasToInt) || (!HasFromValueDecl && !HasToValueDecl)) && @@ -943,16 +967,25 @@ class TemplateDiff { FromInt = FromIter->getAsIntegral(); else if (HasFromValueDecl) FromValueDecl = FromIter->getAsDecl(); - else + else if (!FromNullPtr) FromExpr = GetExpr(FromIter, DefaultNTTPD); if (HasToInt) ToInt = ToIter->getAsIntegral(); else if (HasToValueDecl) ToValueDecl = ToIter->getAsDecl(); - else + else if (!ToNullPtr) ToExpr = GetExpr(ToIter, DefaultNTTPD); + bool TemplateArgumentIsPointerType = + DefaultNTTPD->getType()->isPointerType(); + if (FromExpr && TemplateArgumentIsPointerType) { + FromNullPtr = CheckForNullPtr(FromExpr); + } + if (ToExpr && TemplateArgumentIsPointerType) { + ToNullPtr = CheckForNullPtr(ToExpr); + } + if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) { Tree.SetNode(FromExpr, ToExpr); Tree.SetDefault(FromIter.isEnd() && FromExpr, @@ -972,7 +1005,9 @@ class TemplateDiff { Tree.SetSame(false); Tree.SetKind(DiffTree::Integer); } else { - Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr)); + Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr) || + (FromNullPtr && ToNullPtr)); + Tree.SetNullPtr(FromNullPtr, ToNullPtr); Tree.SetKind(DiffTree::Expression); } } else if (HasFromInt || HasToInt) { @@ -1020,6 +1055,7 @@ class TemplateDiff { } } } + Tree.SetNullPtr(FromNullPtr, ToNullPtr); Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); Tree.SetSame(FromValueDecl && ToValueDecl && FromValueDecl->getCanonicalDecl() == @@ -1187,13 +1223,36 @@ class TemplateDiff { } DeclRefExpr *DRE = dyn_cast(ArgExpr); if (!DRE) { - DRE = cast( - cast(ArgExpr->IgnoreParens())->getSubExpr()); + UnaryOperator *UO = dyn_cast(ArgExpr->IgnoreParens()); + if (!UO) + return nullptr; + DRE = cast(UO->getSubExpr()); } return DRE->getDecl(); } + /// CheckForNullPtr - returns true if the expression can be evaluated as + /// a null pointer + bool CheckForNullPtr(Expr *E) { + assert(E && "Expected expression"); + + E = E->IgnoreParenCasts(); + if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + return true; + + DeclRefExpr *DRE = dyn_cast(E); + if (!DRE) + return false; + + VarDecl *VD = dyn_cast(DRE->getDecl()); + if (!VD || !VD->hasInit()) + return false; + + return VD->getInit()->IgnoreParenCasts()->isNullPointerConstant( + Context, Expr::NPC_ValueDependentIsNull); + } + /// GetTemplateDecl - Retrieves the template template arguments, including /// default arguments. TemplateDecl *GetTemplateDecl(const TSTiterator &Iter, @@ -1300,8 +1359,8 @@ class TemplateDiff { case DiffTree::Expression: { Expr *FromExpr, *ToExpr; Tree.GetNode(FromExpr, ToExpr); - PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), - Tree.NodeIsSame()); + PrintExpr(FromExpr, ToExpr, Tree.FromNullPtr(), Tree.ToNullPtr(), + Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } case DiffTree::TemplateTemplate: { @@ -1327,7 +1386,8 @@ class TemplateDiff { bool FromAddressOf, ToAddressOf; Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf, - Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); + Tree.FromNullPtr(), Tree.ToNullPtr(), Tree.FromDefault(), + Tree.ToDefault(), Tree.NodeIsSame()); return; } case DiffTree::Template: { @@ -1452,36 +1512,41 @@ class TemplateDiff { /// PrintExpr - Prints out the expr template arguments, highlighting argument /// differences. - void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, - bool FromDefault, bool ToDefault, bool Same) { + void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromNullPtr, + bool ToNullPtr, bool FromDefault, bool ToDefault, bool Same) { assert((FromExpr || ToExpr) && "Only one template argument may be missing."); if (Same) { - PrintExpr(FromExpr); + PrintExpr(FromExpr, FromNullPtr); } else if (!PrintTree) { OS << (FromDefault ? "(default) " : ""); Bold(); - PrintExpr(FromExpr); + PrintExpr(FromExpr, FromNullPtr); Unbold(); } else { OS << (FromDefault ? "[(default) " : "["); Bold(); - PrintExpr(FromExpr); + PrintExpr(FromExpr, FromNullPtr); Unbold(); OS << " != " << (ToDefault ? "(default) " : ""); Bold(); - PrintExpr(ToExpr); + PrintExpr(ToExpr, ToNullPtr); Unbold(); OS << ']'; } } /// PrintExpr - Actual formatting and printing of expressions. - void PrintExpr(const Expr *E) { - if (!E) - OS << "(no argument)"; - else + void PrintExpr(const Expr *E, bool NullPtr = false) { + if (E) { E->printPretty(OS, nullptr, Policy); + return; + } + if (NullPtr) { + OS << "nullptr"; + return; + } + OS << "(no argument)"; } /// PrintTemplateTemplate - Handles printing of template template arguments, @@ -1573,35 +1638,46 @@ class TemplateDiff { return true; } + void PrintValueDecl(ValueDecl *VD, bool AddressOf, bool NullPtr) { + if (VD) { + if (AddressOf) + OS << "&"; + OS << VD->getName(); + return; + } + + if (NullPtr) { + OS << "nullptr"; + return; + } + + OS << "(no argument)"; + } + /// PrintDecl - Handles printing of Decl arguments, highlighting /// argument differences. void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, - bool FromAddressOf, bool ToAddressOf, bool FromDefault, - bool ToDefault, bool Same) { - assert((FromValueDecl || ToValueDecl) && + bool FromAddressOf, bool ToAddressOf, bool FromNullPtr, + bool ToNullPtr, bool FromDefault, bool ToDefault, + bool Same) { + assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) && "Only one Decl argument may be NULL"); if (Same) { - OS << FromValueDecl->getName(); + PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr); } else if (!PrintTree) { OS << (FromDefault ? "(default) " : ""); Bold(); - if (FromAddressOf) - OS << "&"; - OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); + PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr); Unbold(); } else { OS << (FromDefault ? "[(default) " : "["); Bold(); - if (FromAddressOf) - OS << "&"; - OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); + PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr); Unbold(); OS << " != " << (ToDefault ? "(default) " : ""); Bold(); - if (ToAddressOf) - OS << "&"; - OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)"); + PrintValueDecl(ToValueDecl, ToAddressOf, ToNullPtr); Unbold(); OS << ']'; } diff --git a/clang/test/Misc/diag-template-diffing.cpp b/clang/test/Misc/diag-template-diffing.cpp index fcafb3325640..55ffb19c33f9 100644 --- a/clang/test/Misc/diag-template-diffing.cpp +++ b/clang/test/Misc/diag-template-diffing.cpp @@ -1129,6 +1129,60 @@ Wrapper> W4 = MakeWrapper>(); // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' } +namespace NullPtr { +template +struct S {}; + +template +struct Wrapper {}; + +template +Wrapper MakeWrapper(); +int global, global2; +constexpr int * ptr = nullptr; +constexpr int * ptr2 = static_cast(0); + +S<&global> s1 = S<&global, ptr>(); +S<&global, nullptr> s2 = S<&global, ptr>(); + +S<&global, nullptr> s3 = S<&global, &global>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], nullptr>' +S<&global, ptr> s4 = S<&global, &global>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], ptr> + +Wrapper> W1 = MakeWrapper>(); +Wrapper(0)>> W2 = MakeWrapper>(); + +Wrapper> W3 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W4 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' + +Wrapper> W5 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W6 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W7 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W8 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W9 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W10 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper(0)>> W11 = + MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W12 = + MakeWrapper(0)>>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' + +Wrapper> W13 = MakeWrapper>(); +// C HECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +Wrapper> W14 = MakeWrapper>(); +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +} + // CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated. // CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated. // CHECK-ELIDE-TREE: {{[0-9]*}} errors generated.