On Fri, Apr 6, 2012 at 3:40 PM, Douglas Gregor <[email protected]> wrote:
> Author: dgregor > Date: Fri Apr 6 17:40:38 2012 > New Revision: 154219 > > URL: http://llvm.org/viewvc/llvm-project?rev=154219&view=rev > Log: > 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>. > > Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=154219&r1=154218&r2=154219&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) > +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Apr 6 17:40:38 2012 > @@ -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)){ > This check accepts values which aren't constant expressions: template<int*> struct S{}; decltype(nullptr) null(); S<null()> s; 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. > + 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; > } > - > - if (ParamType->isNullPtrType()) { > - llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true); > - Converted = TemplateArgument(Zero, Context.NullPtrTy); > - return Owned(Arg); > + > + // Check for a null (member) pointer value. > + Expr::EvalResult EvalResult; > + if (Arg->EvaluateAsRValue(EvalResult, Context) && > EvaluateAsRValue will succeed on anything we can evaluate, including non-constant-expressions and expressions with side-effects: void f(); S<(f(), (int*)0)> s; If you don't care about diagnosing why the expression is non-constant, Expr::isCXX11ConstantExpr is the most convenient interface for this. + ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) || > + (EvalResult.Val.isMemberPointer() && > + !EvalResult.Val.getMemberPointerDecl()))) { > + Converted = TemplateArgument((Decl *)0); > We seem to be missing a check that the null pointer is of the right type. We accept: template<int(*)()> struct S{}; S<(long double*)0> s; > + 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; > } > + > + 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 >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
