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 | |
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')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 108 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 24 |
4 files changed, 108 insertions, 37 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 82d23783f9..fea0fe1e62 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10480,7 +10480,8 @@ namespace { bool MarkReferencedDecls::TraverseTemplateArgument( const TemplateArgument &Arg) { if (Arg.getKind() == TemplateArgument::Declaration) { - S.MarkAnyDeclReferenced(Loc, Arg.getAsDecl()); + if (Decl *D = Arg.getAsDecl()) + S.MarkAnyDeclReferenced(Loc, D); } return Inherited::TraverseTemplateArgument(Arg); 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() && diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b448633381..2ea1e6ff93 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1586,8 +1586,7 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Declaration: if (Arg.getKind() == TemplateArgument::Declaration && - Param.getAsDecl()->getCanonicalDecl() == - Arg.getAsDecl()->getCanonicalDecl()) + isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl())) return Sema::TDK_Success; Info.FirstArg = Param; @@ -1858,8 +1857,7 @@ static bool isSameTemplateArg(ASTContext &Context, Context.getCanonicalType(Y.getAsType()); case TemplateArgument::Declaration: - return X.getAsDecl()->getCanonicalDecl() == - Y.getAsDecl()->getCanonicalDecl(); + return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()); case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: @@ -1925,7 +1923,7 @@ getTrivialTemplateArgumentLoc(Sema &S, case TemplateArgument::Declaration: { Expr *E = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .takeAs<Expr>(); + .takeAs<Expr>(); return TemplateArgumentLoc(TemplateArgument(E), E); } @@ -4410,7 +4408,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, switch (TemplateArg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: - case TemplateArgument::Declaration: + case TemplateArgument::Declaration: break; case TemplateArgument::Type: diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 307cccce8b..4740145fd5 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1113,15 +1113,21 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( type = argExpr->getType(); } else if (arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl()); - - // Find the instantiation of the template argument. This is - // required for nested templates. - VD = cast_or_null<ValueDecl>( - getSema().FindInstantiatedDecl(loc, VD, TemplateArgs)); - if (!VD) - return ExprError(); - + ValueDecl *VD; + if (Decl *D = arg.getAsDecl()) { + VD = cast<ValueDecl>(D); + + // Find the instantiation of the template argument. This is + // required for nested templates. + VD = cast_or_null<ValueDecl>( + getSema().FindInstantiatedDecl(loc, VD, TemplateArgs)); + if (!VD) + return ExprError(); + } else { + // Propagate NULL template argument. + VD = 0; + } + // Derive the type we want the substituted decl to have. This had // better be non-dependent, or these checks will have serious problems. if (parm->isExpandedParameterPack()) { |