<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Apr 6, 2012, at 6:00 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><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 / <<a href="rdar://problem/11193097">rdar://problem/11193097</a>>.<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></div></blockquote><br></div><div>r154407 and r 154424 address your comments, thanks!</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>- Doug</div></body></html>