[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