[cfe-commits] r154219 - in /cfe/trunk: include/clang/AST/TemplateBase.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ASTContext.cpp lib/AST/ASTImporter.cpp lib/AST/DumpXML.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/Templ
Douglas Gregor
dgregor at apple.com
Tue Apr 10 12:52:43 PDT 2012
On Apr 6, 2012, at 6:00 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> On Fri, Apr 6, 2012 at 3:40 PM, Douglas Gregor <dgregor at apple.com> 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;
>
r154407 and r 154424 address your comments, thanks!
- Doug
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120410/eaedc7cf/attachment.html>
More information about the cfe-commits
mailing list