diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-04-06 22:40:38 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-04-06 22:40:38 +0000 |
commit | d2008e2c80d6c9282044ec873a937a17a0f33579 (patch) | |
tree | d3e119b536c83e6fd769fa31a3abac02892a2aed /lib/Sema/SemaTemplate.cpp | |
parent | e35abe1fd3f867ae51d5c68d98578d537eb6beca (diff) |
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>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154219 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 108 |
1 files changed, 87 insertions, 21 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4f6c879317..14558a695c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3527,20 +3527,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, dyn_cast<SubstNonTypeTemplateParmExpr>(Arg)) Arg = subst->getReplacement()->IgnoreImpCasts(); - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg); - if (!DRE) { - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) - << Arg->getSourceRange(); - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. if (Arg->isValueDependent()) { Converted = TemplateArgument(ArgIn); return false; } + + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg); + if (!DRE) { + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + if (!isa<ValueDecl>(DRE->getDecl())) { S.Diag(Arg->getLocStart(), @@ -4048,21 +4049,74 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, 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)){ + 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) && + ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) || + (EvalResult.Val.isMemberPointer() && + !EvalResult.Val.getMemberPointerDecl()))) { + Converted = TemplateArgument((Decl *)0); + 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 @@ -4255,6 +4309,18 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc) { assert(Arg.getKind() == TemplateArgument::Declaration && "Only declaration template arguments permitted here"); + + // For a NULL non-type template argument, return nullptr casted to the + // parameter's type. + if (!Arg.getAsDecl()) { + return ImpCastExprToType( + new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc), + ParamType, + ParamType->getAs<MemberPointerType>() + ? CK_NullToMemberPointer + : CK_NullToPointer); + } + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); if (VD->getDeclContext()->isRecord() && |