[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

Richard Smith richard at metafoo.co.uk
Fri Apr 6 18:00:25 PDT 2012


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;


> +      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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120406/67d4e4c2/attachment.html>


More information about the cfe-commits mailing list