From ca240a9005dfbf8ca676a9825192d8feeb939ae8 Mon Sep 17 00:00:00 2001
From: Richard Smith <richard-llvm@metafoo.co.uk>
Date: Thu, 24 Jul 2014 02:27:39 +0000
Subject: [PATCH] Take the canonical type when forming a canonical template
 argument with 'nullptr' value. Fixes profiling of such template arguments to
 always give the same value.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@213834 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaTemplate.cpp                    |  9 ++++++---
 test/SemaTemplate/temp_arg_nontype_cxx11.cpp | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d0f9b84d5d2..d81f6513688 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4438,7 +4438,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
     switch (NPV) {
     case NPV_NullPointer:
       S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
-      Converted = TemplateArgument(ParamType, /*isNullPtr=*/true);
+      Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+                                   /*isNullPtr=*/true);
       return false;
 
     case NPV_Error:
@@ -4633,7 +4634,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
     return true;
   case NPV_NullPointer:
     S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
-    Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
+    Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+                                 /*isNullPtr*/true);
     if (S.Context.getTargetInfo().getCXXABI().isMicrosoft())
       S.RequireCompleteType(Arg->getExprLoc(), ParamType, 0);
     return false;
@@ -5089,7 +5091,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
       
     case NPV_NullPointer:
       Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
-      Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
+      Converted = TemplateArgument(Context.getCanonicalType(ParamType),
+                                   /*isNullPtr*/true);
       return Arg;
     }
   }
diff --git a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
index d773c6436fb..15c9c2560a9 100644
--- a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
+++ b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
@@ -8,3 +8,18 @@ namespace PR15360 {
     f<int[3], int*, nullptr>(); // expected-note{{in instantiation of}}
   }
 }
+
+namespace CanonicalNullptr {
+  template<typename T> struct get { typedef T type; };
+  struct X {};
+  template<typename T, typename get<T *>::type P = nullptr> struct A {};
+  template<typename T, typename get<decltype((T(), nullptr))>::type P = nullptr> struct B {};
+  template<typename T, typename get<T X::*>::type P = nullptr> struct C {};
+
+  template<typename T> A<T> MakeA();
+  template<typename T> B<T> MakeB();
+  template<typename T> C<T> MakeC();
+  A<int> a = MakeA<int>();
+  B<int> b = MakeB<int>();
+  C<int> c = MakeC<int>();
+}
-- 
GitLab