diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index 06e4181e713c..65f54600c009 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -101,7 +101,6 @@ public: /// declaration, which is either an external declaration or a /// template declaration. TemplateArgument(Decl *D) : Kind(Declaration) { - // FIXME: Need to be sure we have the "canonical" declaration! TypeOrValue = reinterpret_cast(D); } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6735bfcb4576..ffe7be300a3b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2339,6 +2339,8 @@ def err_template_arg_not_integral_or_enumeral : Error< def err_template_arg_not_ice : Error< "non-type template argument of type %0 is not an integral constant " "expression">; +def err_template_arg_untyped_null_constant : Error< + "null non-type template argument must be cast to template parameter type %0">; def err_deduced_non_type_template_arg_type_mismatch : Error< "deduced non-type template argument does not have the same type as the " "its corresponding template parameter (%0 vs %1)">; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 15f85ba9c482..acf5e0bbc9af 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3313,8 +3313,11 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { case TemplateArgument::Expression: return Arg; - case TemplateArgument::Declaration: - return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl()); + case TemplateArgument::Declaration: { + if (Decl *D = Arg.getAsDecl()) + return TemplateArgument(D->getCanonicalDecl()); + return TemplateArgument((Decl*)0); + } case TemplateArgument::Template: return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 621658c7f0ac..3879907ec6da 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -325,6 +325,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral()); case TemplateArgument::Declaration: + if (!Arg1.getAsDecl() || !Arg2.getAsDecl()) + return !Arg1.getAsDecl() && !Arg2.getAsDecl(); return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); case TemplateArgument::Template: diff --git a/clang/lib/AST/DumpXML.cpp b/clang/lib/AST/DumpXML.cpp index b180e808ab40..4c7cd8a6793b 100644 --- a/clang/lib/AST/DumpXML.cpp +++ b/clang/lib/AST/DumpXML.cpp @@ -320,7 +320,8 @@ struct XMLDumper : public XMLDeclVisitor, break; case TemplateArgument::Declaration: { - visitDeclRef(A.getAsDecl()); + if (Decl *D = A.getAsDecl()) + visitDeclRef(D); break; } case TemplateArgument::Integral: { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 0d8490e137de..4ef169d18995 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1743,8 +1743,10 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, // parameters are constant expressions even if they're non-const. // In C, such things can also be folded, although they are not ICEs. const VarDecl *VD = dyn_cast(D); - if (const VarDecl *VDef = VD->getDefinition(Info.Ctx)) - VD = VDef; + if (VD) { + if (const VarDecl *VDef = VD->getDefinition(Info.Ctx)) + VD = VDef; + } if (!VD || VD->isInvalidDecl()) { Info.Diag(Conv); return false; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5457036920b7..d7b635454011 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3118,12 +3118,22 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, case TemplateArgument::Declaration: { assert(P && "Missing template parameter for declaration argument"); // ::= L E # external name - + // ::= L 0 E // Clang produces AST's where pointer-to-member-function expressions // and pointer-to-function expressions are represented as a declaration not // an expression. We compensate for it here to produce the correct mangling. - NamedDecl *D = cast(A.getAsDecl()); const NonTypeTemplateParmDecl *Parameter = cast(P); + + // Handle NULL pointer arguments. + if (!A.getAsDecl()) { + Out << "L"; + mangleType(Parameter->getType()); + Out << "0E"; + break; + } + + + NamedDecl *D = cast(A.getAsDecl()); bool compensateMangling = !Parameter->getType()->isReferenceType(); if (compensateMangling) { Out << 'X'; diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 7e6bae2b2678..531e03e302b2 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -80,9 +80,13 @@ bool TemplateArgument::isDependent() const { return true; case Declaration: - if (DeclContext *DC = dyn_cast(getAsDecl())) - return DC->isDependentContext(); - return getAsDecl()->getDeclContext()->isDependentContext(); + if (Decl *D = getAsDecl()) { + if (DeclContext *DC = dyn_cast(D)) + return DC->isDependentContext(); + return D->getDeclContext()->isDependentContext(); + } + + return false; case Integral: // Never dependent @@ -118,10 +122,13 @@ bool TemplateArgument::isInstantiationDependent() const { return true; case Declaration: - if (DeclContext *DC = dyn_cast(getAsDecl())) - return DC->isDependentContext(); - return getAsDecl()->getDeclContext()->isDependentContext(); - + if (Decl *D = getAsDecl()) { + if (DeclContext *DC = dyn_cast(D)) + return DC->isDependentContext(); + return D->getDeclContext()->isDependentContext(); + } + return false; + case Integral: // Never dependent return false; @@ -322,16 +329,14 @@ void TemplateArgument::print(const PrintingPolicy &Policy, } case Declaration: { - bool Unnamed = true; if (NamedDecl *ND = dyn_cast_or_null(getAsDecl())) { if (ND->getDeclName()) { - Unnamed = false; Out << *ND; + } else { + Out << ""; } - } - - if (Unnamed) { - Out << ""; + } else { + Out << "nullptr"; } break; } @@ -488,7 +493,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB << Arg.getAsType(); case TemplateArgument::Declaration: - return DB << Arg.getAsDecl(); + if (Decl *D = Arg.getAsDecl()) + return DB << D; + return DB << "nullptr"; case TemplateArgument::Integral: return DB << Arg.getAsIntegral()->toString(10); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 664a658160e8..3bf80e797244 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -264,8 +264,9 @@ void TypePrinter::printRValueReference(const RValueReferenceType *T, void TypePrinter::printMemberPointer(const MemberPointerType *T, std::string &S) { - std::string C; - print(QualType(T->getClass(), 0), C); + PrintingPolicy InnerPolicy(Policy); + Policy.SuppressTag = true; + std::string C = QualType(T->getClass(), 0).getAsString(InnerPolicy); C += "::*"; S = C + S; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 82d23783f917..fea0fe1e62b3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4f6c87931752..14558a695cd4 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3527,20 +3527,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, dyn_cast(Arg)) Arg = subst->getReplacement()->IgnoreImpCasts(); - DeclRefExpr *DRE = dyn_cast(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(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(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; + } + + // 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; } - if (ParamType->isNullPtrType()) { - llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true); - Converted = TemplateArgument(Zero, Context.NullPtrTy); - return Owned(Arg); - } + 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() + ? CK_NullToMemberPointer + : CK_NullToPointer); + } + ValueDecl *VD = cast(Arg.getAsDecl()); if (VD->getDeclContext()->isRecord() && diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b44863338121..2ea1e6ff9341 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/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(); + .takeAs(); 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/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 307cccce8bcf..4740145fd5ac 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1113,15 +1113,21 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( type = argExpr->getType(); } else if (arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast(arg.getAsDecl()); - - // Find the instantiation of the template argument. This is - // required for nested templates. - VD = cast_or_null( - getSema().FindInstantiatedDecl(loc, VD, TemplateArgs)); - if (!VD) - return ExprError(); + ValueDecl *VD; + if (Decl *D = arg.getAsDecl()) { + VD = cast(D); + // Find the instantiation of the template argument. This is + // required for nested templates. + VD = cast_or_null( + 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()) { diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp new file mode 100644 index 000000000000..d72f26ecdbc0 --- /dev/null +++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify + +namespace std { + typedef decltype(nullptr) nullptr_t; +} + +template struct IP { // expected-note 2 {{template parameter is declared here}} + IP *ip2; +}; + +constexpr std::nullptr_t get_nullptr() { return nullptr; } + +std::nullptr_t np; + +IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}} +IP<(0)> ip1; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}} +IP ip2; +IP ip3; +IP<(int*)0> ip4; +IP ip5; + +struct X { }; +template struct PM { // expected-note 2 {{template parameter is declared here}} + PM *pm2; +}; + +PM<0> pm0; // expected-error{{null non-type template argument must be cast to template parameter type 'int X::*'}} +PM<(0)> pm1; // expected-error{{null non-type template argument must be cast to template parameter type 'int X::*'}} +PM pm2; +PM pm3; +PM<(int X::*)0> pm4; +PM pm5; + +template struct PMF { // expected-note 2 {{template parameter is declared here}} + PMF *pmf2; +}; + +PMF<0> pmf0; // expected-error{{null non-type template argument must be cast to template parameter type 'int (X::*)(int)'}} +PMF<(0)> pmf1; // expected-error{{null non-type template argument must be cast to template parameter type 'int (X::*)(int)'}} +PMF pmf2; +PMF pmf3; +PMF<(int (X::*)(int))0> pmf4; +PMF pmf5; + + +template struct NP { // expected-note 2{{template parameter is declared here}} + NP *np2; +}; + +NP np1; +NP np2; +NP np3; +NP<0> np4; // expected-error{{null non-type template argument must be cast to template parameter type 'std::nullptr_t' (aka 'nullptr_t')}} +constexpr int i = 7; +NP np5; // expected-error{{non-type template argument of type 'const int' cannot be converted to a value of type 'std::nullptr_t'}} diff --git a/clang/test/CodeGenCXX/mangle-nullptr-arg.cpp b/clang/test/CodeGenCXX/mangle-nullptr-arg.cpp new file mode 100644 index 000000000000..393de0b0ece9 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-nullptr-arg.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s + +template struct IP {}; + +// CHECK: define void @_Z5test12IPILPi0EE +void test1(IP) {} + +struct X{ }; +template struct PM {}; + +// CHECK: define void @_Z5test22PMILM1Xi0EE +void test2(PM) { } + diff --git a/clang/test/FixIt/fixit-cxx0x.cpp b/clang/test/FixIt/fixit-cxx0x.cpp index 997d73abfb54..b6cc2c08b031 100644 --- a/clang/test/FixIt/fixit-cxx0x.cpp +++ b/clang/test/FixIt/fixit-cxx0x.cpp @@ -104,3 +104,7 @@ namespace TestMisplacedEllipsisRecovery { template ...Foo, // expected-error {{template template parameter requires 'class' after the parameter list}} template>>> // expected-error 3 {{template template parameter requires 'class' after the parameter list}} void func(); + +template struct IP { }; // expected-note{{declared here}} +IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}} +