<div class="gmail_quote">On Fri, Apr 6, 2012 at 3:40 PM, Douglas Gregor <span dir="ltr"><<a href="mailto:dgregor@apple.com" target="_blank">dgregor@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Author: dgregor<br>
Date: Fri Apr  6 17:40:38 2012<br>
New Revision: 154219<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=154219&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=154219&view=rev</a><br>
Log:<br>
Implement support for null non-type template arguments for non-type<br>
template parameters of pointer, pointer-to-member, or nullptr_t<br>
type in C++11. Fixes PR9700 / <rdar://problem/11193097>.<br><br>
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=154219&r1=154218&r2=154219&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=154219&r1=154218&r2=154219&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Apr  6 17:40:38 2012<br>@@ -4048,21 +4049,74 @@<br>
   QualType ArgType = Arg->getType();<br>
   DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction<br>
<br>
-  // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion<br>
-  // from a template argument of type std::nullptr_t to a non-type<br>
-  // template parameter of type pointer to object, pointer to<br>
-  // function, or pointer-to-member, respectively.<br>
-  if (ArgType->isNullPtrType()) {<br>
-    if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {<br>
-      Converted = TemplateArgument((NamedDecl *)0);<br>
-      return Owned(Arg);<br>
+  // C++11 [temp.arg.nontype]p1:<br>
+  //   - a constant expression that evaluates to a null pointer value (4.10); or<br>
+  //   - a constant expression that evaluates to a null member pointer value<br>
+  //     (4.11); or<br>
+  //   - an address constant expression of type std::nullptr_t<br>
+  if (getLangOpts().CPlusPlus0x &&<br>
+      (ParamType->isPointerType() || ParamType->isMemberPointerType() ||<br>
+       ParamType->isNullPtrType()) &&<br>
+      !Arg->isValueDependent() && !Arg->isTypeDependent()) {<br>
+    if (Expr::NullPointerConstantKind NPC<br>
+          = Arg->isNullPointerConstant(Context, Expr::NPC_NeverValueDependent)){<br></blockquote><div><br></div><div>This check accepts values which aren't constant expressions:</div><div><br></div><div>template<int*> struct S{};</div>

<div>decltype(nullptr) null();</div><div>S<null()> s;</div><div><br></div><div>Here, after conversion to a pointer type, null() is a null pointer value (by 4.10/1, it's a prvalue of type std::nullptr_t), but it's not a constant expression.</div>

<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      if (NPC != Expr::NPCK_CXX0X_nullptr) {<br>
+        // C++11 [temp.arg.nontype]p5b2:<br>
+        //   if the template-argument is of type std::nullptr_t, the null<br>
+        //   pointer conversion (4.10) is applied. [ Note: In particular,<br>
+        //   neither the null pointer conversion for a zero-valued integral<br>
+        //   constant expression (4.10) nor the derived-to-base conversion<br>
+        //   (4.10) are applied. Although 0 is a valid template-argument for a<br>
+        //   non-type template-parameter of integral type, it is not a valid<br>
+        //   template-argument for a non-type template-parameter of pointer<br>
+        //   type. However, both (int*)0 and nullptr are valid<br>
+        //   template-arguments for a non-type template-parameter of type<br>
+        //   "pointer to int." â€” end note ]<br>
+        bool ObjCLifetimeConversion;<br>
+        if (!Context.hasSameUnqualifiedType(ArgType, ParamType) &&<br>
+            !IsQualificationConversion(ArgType, ParamType, false,<br>
+                                       ObjCLifetimeConversion)) {<br>
+          {<br>
+            SemaDiagnosticBuilder DB<br>
+              = Diag(Arg->getExprLoc(),<br>
+                     diag::err_template_arg_untyped_null_constant);<br>
+            DB << ParamType;<br>
+<br>
+            if (ArgType->isIntegralType(Context)) {<br>
+              std::string Code = "(" + ParamType.getAsString() + ")";<br>
+              DB << FixItHint::CreateInsertion(Arg->getLocStart(), Code);<br>
+            }<br>
+          }<br>
+          Diag(Param->getLocation(), diag::note_template_param_here);<br>
+        }<br>
+      }<br>
+<br>
+      Converted = TemplateArgument((Decl *)0);<br>
+      return false;<br>
     }<br>
-<br>
-    if (ParamType->isNullPtrType()) {<br>
-      llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true);<br>
-      Converted = TemplateArgument(Zero, Context.NullPtrTy);<br>
-      return Owned(Arg);<br>
+<br>
+    // Check for a null (member) pointer value.<br>
+    Expr::EvalResult EvalResult;<br>
+    if (Arg->EvaluateAsRValue(EvalResult, Context) &&<br></blockquote><div><br></div><div>EvaluateAsRValue will succeed on anything we can evaluate, including non-constant-expressions and expressions with side-effects:</div>

<div><br></div><div>void f();</div><div>S<(f(), (int*)0)> s;</div><div><br></div><div>If you don't care about diagnosing why the expression is non-constant, Expr::isCXX11ConstantExpr is the most convenient interface for this.</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+        ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||<br>
+         (EvalResult.Val.isMemberPointer() &&<br>
+          !EvalResult.Val.getMemberPointerDecl()))) {<br>
+      Converted = TemplateArgument((Decl *)0);<br></blockquote><div><br></div><div>We seem to be missing a check that the null pointer is of the right type. We accept:</div><div><br></div><div>template<int(*)()> struct S{};</div>
<div>S<(long double*)0> s;</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      return false;<br>
+    }<br>
+  }<br>
+<br>
+  // If we haven't dealt with a null pointer-typed parameter yet, do so now.<br>
+  if (ParamType->isNullPtrType()) {<br>
+    if (Arg->isTypeDependent() || Arg->isValueDependent()) {<br>
+      Converted = TemplateArgument(Arg);<br>
+      return false;<br>
     }<br>
+<br>
+    Diag(Arg->getExprLoc(), diag::err_template_arg_not_convertible)<br>
+      << Arg->getType() << ParamType;<br>
+    Diag(Param->getLocation(), diag::note_template_param_here);<br>
+    return true;<br>
   }<br>
<br>
   // Handle pointer-to-function, reference-to-function, and<br></blockquote></div>