Implement support for null non-type template arguments for non-type
template parameters of pointer, pointer-to-member, or nullptr_t
type in C++11. Fixes PR9700 / <rdar://problem/11193097>.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154219 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 06e4181..65f5460 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -101,7 +101,6 @@
   /// declaration, which is either an external declaration or a
   /// template declaration.
   TemplateArgument(Decl *D) : Kind(Declaration) {
-    // FIXME: Need to be sure we have the "canonical" declaration!
     TypeOrValue = reinterpret_cast<uintptr_t>(D);
   }
 
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6735bfc..ffe7be3 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2339,6 +2339,8 @@
 def err_template_arg_not_ice : Error<
   "non-type template argument of type %0 is not an integral constant "
   "expression">;
+def err_template_arg_untyped_null_constant : Error<
+  "null non-type template argument must be cast to template parameter type %0">;
 def err_deduced_non_type_template_arg_type_mismatch : Error<
   "deduced non-type template argument does not have the same type as the "
   "its corresponding template parameter (%0 vs %1)">;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 15f85ba..acf5e0b 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3313,8 +3313,11 @@
     case TemplateArgument::Expression:
       return Arg;
 
-    case TemplateArgument::Declaration:
-      return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl());
+    case TemplateArgument::Declaration: {
+      if (Decl *D = Arg.getAsDecl())
+          return TemplateArgument(D->getCanonicalDecl());
+      return TemplateArgument((Decl*)0);
+    }
 
     case TemplateArgument::Template:
       return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 621658c..3879907 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -325,6 +325,8 @@
     return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral());
       
   case TemplateArgument::Declaration:
+    if (!Arg1.getAsDecl() || !Arg2.getAsDecl())
+      return !Arg1.getAsDecl() && !Arg2.getAsDecl();
     return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
       
   case TemplateArgument::Template:
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index b180e80..4c7cd8a 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -320,7 +320,8 @@
       break;
         
     case TemplateArgument::Declaration: {
-      visitDeclRef(A.getAsDecl());
+      if (Decl *D = A.getAsDecl())
+        visitDeclRef(D);
       break;
     }
     case TemplateArgument::Integral: {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 0d8490e..4ef169d 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1743,8 +1743,10 @@
     // parameters are constant expressions even if they're non-const.
     // In C, such things can also be folded, although they are not ICEs.
     const VarDecl *VD = dyn_cast<VarDecl>(D);
-    if (const VarDecl *VDef = VD->getDefinition(Info.Ctx))
-      VD = VDef;
+    if (VD) {
+      if (const VarDecl *VDef = VD->getDefinition(Info.Ctx))
+        VD = VDef;
+    }
     if (!VD || VD->isInvalidDecl()) {
       Info.Diag(Conv);
       return false;
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 5457036..d7b6354 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -3118,12 +3118,22 @@
   case TemplateArgument::Declaration: {
     assert(P && "Missing template parameter for declaration argument");
     //  <expr-primary> ::= L <mangled-name> E # external name
-
+    //  <expr-primary> ::= L <type> 0 E
     // Clang produces AST's where pointer-to-member-function expressions
     // and pointer-to-function expressions are represented as a declaration not
     // an expression. We compensate for it here to produce the correct mangling.
-    NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
     const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
+
+    // Handle NULL pointer arguments.
+    if (!A.getAsDecl()) {
+      Out << "L";
+      mangleType(Parameter->getType());
+      Out << "0E";
+      break;
+    }
+    
+
+    NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
     bool compensateMangling = !Parameter->getType()->isReferenceType();
     if (compensateMangling) {
       Out << 'X';
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 7e6bae2..531e03e 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -80,9 +80,13 @@
     return true;
 
   case Declaration:
-    if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
-      return DC->isDependentContext();
-    return getAsDecl()->getDeclContext()->isDependentContext();
+    if (Decl *D = getAsDecl()) {
+      if (DeclContext *DC = dyn_cast<DeclContext>(D))
+        return DC->isDependentContext();
+      return D->getDeclContext()->isDependentContext();
+    }
+      
+    return false;
 
   case Integral:
     // Never dependent
@@ -118,10 +122,13 @@
     return true;
     
   case Declaration:
-    if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
-      return DC->isDependentContext();
-    return getAsDecl()->getDeclContext()->isDependentContext();
-    
+    if (Decl *D = getAsDecl()) {
+      if (DeclContext *DC = dyn_cast<DeclContext>(D))
+        return DC->isDependentContext();
+      return D->getDeclContext()->isDependentContext();
+    }
+    return false;
+      
   case Integral:
     // Never dependent
     return false;
@@ -322,16 +329,14 @@
   }
     
   case Declaration: {
-    bool Unnamed = true;
     if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) {
       if (ND->getDeclName()) {
-        Unnamed = false;
         Out << *ND;
+      } else {
+        Out << "<anonymous>";
       }
-    }
-    
-    if (Unnamed) {
-      Out << "<anonymous>";
+    } else {
+      Out << "nullptr";
     }
     break;
   }
@@ -488,7 +493,9 @@
     return DB << Arg.getAsType();
       
   case TemplateArgument::Declaration:
-    return DB << Arg.getAsDecl();
+    if (Decl *D = Arg.getAsDecl())
+      return DB << D;
+    return DB << "nullptr";
       
   case TemplateArgument::Integral:
     return DB << Arg.getAsIntegral()->toString(10);
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 664a658..3bf80e7 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -264,8 +264,9 @@
 
 void TypePrinter::printMemberPointer(const MemberPointerType *T, 
                                      std::string &S) { 
-  std::string C;
-  print(QualType(T->getClass(), 0), C);
+  PrintingPolicy InnerPolicy(Policy);
+  Policy.SuppressTag = true;
+  std::string C = QualType(T->getClass(), 0).getAsString(InnerPolicy);
   C += "::*";
   S = C + S;
   
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 82d2378..fea0fe1 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10480,7 +10480,8 @@
 bool MarkReferencedDecls::TraverseTemplateArgument(
   const TemplateArgument &Arg) {
   if (Arg.getKind() == TemplateArgument::Declaration) {
-    S.MarkAnyDeclReferenced(Loc, Arg.getAsDecl());
+    if (Decl *D = Arg.getAsDecl())
+      S.MarkAnyDeclReferenced(Loc, D);
   }
 
   return Inherited::TraverseTemplateArgument(Arg);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 4f6c879..14558a6 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3527,20 +3527,21 @@
            dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
     Arg = subst->getReplacement()->IgnoreImpCasts();
 
-  DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
-  if (!DRE) {
-    S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
-      << Arg->getSourceRange();
-    S.Diag(Param->getLocation(), diag::note_template_param_here);
-    return true;
-  }
-
   // Stop checking the precise nature of the argument if it is value dependent,
   // it should be checked when instantiated.
   if (Arg->isValueDependent()) {
     Converted = TemplateArgument(ArgIn);
     return false;
   }
+  
+  DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
+  if (!DRE) {
+    S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+    << Arg->getSourceRange();
+    S.Diag(Param->getLocation(), diag::note_template_param_here);
+    return true;
+  }
+  
 
   if (!isa<ValueDecl>(DRE->getDecl())) {
     S.Diag(Arg->getLocStart(),
@@ -4048,21 +4049,74 @@
   QualType ArgType = Arg->getType();
   DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction
 
-  // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion
-  // from a template argument of type std::nullptr_t to a non-type
-  // template parameter of type pointer to object, pointer to
-  // function, or pointer-to-member, respectively.
-  if (ArgType->isNullPtrType()) {
-    if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
-      Converted = TemplateArgument((NamedDecl *)0);
-      return Owned(Arg);
+  // C++11 [temp.arg.nontype]p1:
+  //   - a constant expression that evaluates to a null pointer value (4.10); or
+  //   - a constant expression that evaluates to a null member pointer value
+  //     (4.11); or
+  //   - an address constant expression of type std::nullptr_t
+  if (getLangOpts().CPlusPlus0x &&
+      (ParamType->isPointerType() || ParamType->isMemberPointerType() ||
+       ParamType->isNullPtrType()) &&
+      !Arg->isValueDependent() && !Arg->isTypeDependent()) {
+    if (Expr::NullPointerConstantKind NPC
+          = Arg->isNullPointerConstant(Context, Expr::NPC_NeverValueDependent)){
+      if (NPC != Expr::NPCK_CXX0X_nullptr) {
+        // C++11 [temp.arg.nontype]p5b2:
+        //   if the template-argument is of type std::nullptr_t, the null
+        //   pointer conversion (4.10) is applied. [ Note: In particular,
+        //   neither the null pointer conversion for a zero-valued integral
+        //   constant expression (4.10) nor the derived-to-base conversion
+        //   (4.10) are applied. Although 0 is a valid template-argument for a
+        //   non-type template-parameter of integral type, it is not a valid
+        //   template-argument for a non-type template-parameter of pointer
+        //   type. However, both (int*)0 and nullptr are valid
+        //   template-arguments for a non-type template-parameter of type
+        //   "pointer to int." — end note ]
+        bool ObjCLifetimeConversion;
+        if (!Context.hasSameUnqualifiedType(ArgType, ParamType) &&
+            !IsQualificationConversion(ArgType, ParamType, false,
+                                       ObjCLifetimeConversion)) {
+          {
+            SemaDiagnosticBuilder DB
+              = Diag(Arg->getExprLoc(),
+                     diag::err_template_arg_untyped_null_constant);
+            DB << ParamType;
+                
+            if (ArgType->isIntegralType(Context)) {
+              std::string Code = "(" + ParamType.getAsString() + ")";
+              DB << FixItHint::CreateInsertion(Arg->getLocStart(), Code);
+            }
+          }
+          Diag(Param->getLocation(), diag::note_template_param_here);
+        }
+      }
+      
+      Converted = TemplateArgument((Decl *)0);
+      return false;
+    }
+
+    // Check for a null (member) pointer value.
+    Expr::EvalResult EvalResult;
+    if (Arg->EvaluateAsRValue(EvalResult, Context) &&
+        ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||
+         (EvalResult.Val.isMemberPointer() &&
+          !EvalResult.Val.getMemberPointerDecl()))) {
+      Converted = TemplateArgument((Decl *)0);
+      return false;
+    }
+  }
+  
+  // If we haven't dealt with a null pointer-typed parameter yet, do so now.
+  if (ParamType->isNullPtrType()) {
+    if (Arg->isTypeDependent() || Arg->isValueDependent()) {
+      Converted = TemplateArgument(Arg);
+      return false;
     }
     
-    if (ParamType->isNullPtrType()) {
-      llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true);
-      Converted = TemplateArgument(Zero, Context.NullPtrTy);
-      return Owned(Arg);
-    }
+    Diag(Arg->getExprLoc(), diag::err_template_arg_not_convertible)
+      << Arg->getType() << ParamType;
+    Diag(Param->getLocation(), diag::note_template_param_here);
+    return true;
   }
 
   // Handle pointer-to-function, reference-to-function, and
@@ -4255,6 +4309,18 @@
                                               SourceLocation Loc) {
   assert(Arg.getKind() == TemplateArgument::Declaration &&
          "Only declaration template arguments permitted here");
+  
+  // For a NULL non-type template argument, return nullptr casted to the
+  // parameter's type.
+  if (!Arg.getAsDecl()) {
+    return ImpCastExprToType(
+             new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc),
+                             ParamType,
+                             ParamType->getAs<MemberPointerType>()
+                               ? CK_NullToMemberPointer
+                               : CK_NullToPointer);
+  }
+  
   ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
 
   if (VD->getDeclContext()->isRecord() &&
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b448633..2ea1e6f 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1586,8 +1586,7 @@
 
   case TemplateArgument::Declaration:
     if (Arg.getKind() == TemplateArgument::Declaration &&
-        Param.getAsDecl()->getCanonicalDecl() ==
-          Arg.getAsDecl()->getCanonicalDecl())
+        isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
       return Sema::TDK_Success;
 
     Info.FirstArg = Param;
@@ -1858,8 +1857,7 @@
              Context.getCanonicalType(Y.getAsType());
 
     case TemplateArgument::Declaration:
-      return X.getAsDecl()->getCanonicalDecl() ==
-             Y.getAsDecl()->getCanonicalDecl();
+      return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
 
     case TemplateArgument::Template:
     case TemplateArgument::TemplateExpansion:
@@ -1925,7 +1923,7 @@
   case TemplateArgument::Declaration: {
     Expr *E
       = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
-    .takeAs<Expr>();
+          .takeAs<Expr>();
     return TemplateArgumentLoc(TemplateArgument(E), E);
   }
 
@@ -4410,7 +4408,7 @@
   switch (TemplateArg.getKind()) {
   case TemplateArgument::Null:
   case TemplateArgument::Integral:
-    case TemplateArgument::Declaration:
+  case TemplateArgument::Declaration:
     break;
 
   case TemplateArgument::Type:
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 307cccc..4740145 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1113,15 +1113,21 @@
     type = argExpr->getType();
 
   } else if (arg.getKind() == TemplateArgument::Declaration) {
-    ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl());
+    ValueDecl *VD;
+    if (Decl *D = arg.getAsDecl()) {
+      VD = cast<ValueDecl>(D);
 
-    // Find the instantiation of the template argument.  This is
-    // required for nested templates.
-    VD = cast_or_null<ValueDecl>(
-                       getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
-    if (!VD)
-      return ExprError();
-
+      // Find the instantiation of the template argument.  This is
+      // required for nested templates.
+      VD = cast_or_null<ValueDecl>(
+             getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
+      if (!VD)
+        return ExprError();
+    } else {
+      // Propagate NULL template argument.
+      VD = 0;
+    }
+    
     // Derive the type we want the substituted decl to have.  This had
     // better be non-dependent, or these checks will have serious problems.
     if (parm->isExpandedParameterPack()) {
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
new file mode 100644
index 0000000..d72f26e
--- /dev/null
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+namespace std {
+  typedef decltype(nullptr) nullptr_t;
+}
+
+template<int *ip> struct IP {  // expected-note 2 {{template parameter is declared here}}
+  IP<ip> *ip2;
+};
+
+constexpr std::nullptr_t get_nullptr() { return nullptr; }
+
+std::nullptr_t np;
+
+IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
+IP<(0)> ip1; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
+IP<nullptr> ip2;
+IP<get_nullptr()> ip3;
+IP<(int*)0> ip4;
+IP<np> ip5;
+
+struct X { };
+template<int X::*pm> struct PM { // expected-note 2 {{template parameter is declared here}}
+  PM<pm> *pm2;
+};
+
+PM<0> pm0; // expected-error{{null non-type template argument must be cast to template parameter type 'int X::*'}}
+PM<(0)> pm1; // expected-error{{null non-type template argument must be cast to template parameter type 'int X::*'}}
+PM<nullptr> pm2;
+PM<get_nullptr()> pm3;
+PM<(int X::*)0> pm4;
+PM<np> pm5;
+
+template<int (X::*pmf)(int)> struct PMF { // expected-note 2 {{template parameter is declared here}}
+  PMF<pmf> *pmf2;
+};
+
+PMF<0> pmf0; // expected-error{{null non-type template argument must be cast to template parameter type 'int (X::*)(int)'}}
+PMF<(0)> pmf1; // expected-error{{null non-type template argument must be cast to template parameter type 'int (X::*)(int)'}}
+PMF<nullptr> pmf2;
+PMF<get_nullptr()> pmf3;
+PMF<(int (X::*)(int))0> pmf4;
+PMF<np> pmf5;
+
+
+template<std::nullptr_t np> struct NP { // expected-note 2{{template parameter is declared here}}
+  NP<np> *np2;
+};
+
+NP<nullptr> np1;
+NP<np> np2;
+NP<get_nullptr()> np3;
+NP<0> np4; // expected-error{{null non-type template argument must be cast to template parameter type 'std::nullptr_t' (aka 'nullptr_t')}}
+constexpr int i = 7;
+NP<i> np5; // expected-error{{non-type template argument of type 'const int' cannot be converted to a value of type 'std::nullptr_t'}}
diff --git a/test/CodeGenCXX/mangle-nullptr-arg.cpp b/test/CodeGenCXX/mangle-nullptr-arg.cpp
new file mode 100644
index 0000000..393de0b
--- /dev/null
+++ b/test/CodeGenCXX/mangle-nullptr-arg.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+template<int *ip> struct IP {};
+
+// CHECK: define void @_Z5test12IPILPi0EE
+void test1(IP<nullptr>) {}
+
+struct X{ };
+template<int X::*pm> struct PM {};
+
+// CHECK: define void @_Z5test22PMILM1Xi0EE
+void test2(PM<nullptr>) { }
+
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 997d73a..b6cc2c0 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -104,3 +104,7 @@
 template<template<typename> ...Foo, // expected-error {{template template parameter requires 'class' after the parameter list}}
          template<template<template<typename>>>> // expected-error 3 {{template template parameter requires 'class' after the parameter list}}
 void func();
+
+template<int *ip> struct IP { }; // expected-note{{declared here}}
+IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
+