From 49ba3cabdd74396df02e8ef68fdcd95690217e28 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 12 Nov 2009 18:38:13 +0000 Subject: [PATCH] Recognize (and check) pointer-to-member template arguments that are non-type template parameters or constants of pointer-to-member type. Once checked, be sure to retain those pointer-to-member constants as expressions if they are dependent, or as declarations if they are not dependent. llvm-svn: 87010 --- clang/lib/Sema/Sema.h | 3 +- clang/lib/Sema/SemaTemplate.cpp | 61 +++++++++++-------- .../instantiate-member-pointers.cpp | 13 ++++ 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 2557dfeb8973..4a6d01b4e24a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2615,7 +2615,8 @@ public: DeclaratorInfo *Arg); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); - bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); + bool CheckTemplateArgumentPointerToMember(Expr *Arg, + TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index af7634ae86aa..07d7839455f0 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1187,11 +1187,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, QualType CanonType; - if (TemplateSpecializationType::anyDependentTemplateArguments( + if (Name.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, - NumTemplateArgs) || - isa(Template) || - Template->getDeclContext()->isDependentContext()) { + NumTemplateArgs)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -2088,8 +2087,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, /// \brief Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -bool -Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { +bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, + TemplateArgument &Converted) { bool Invalid = false; // See through any implicit casts we added to fix the type. @@ -2120,13 +2119,33 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { Arg = Parens->getSubExpr(); } - if (UnaryOperator *UnOp = dyn_cast(Arg)) + // A pointer-to-member constant written &Class::member. + if (UnaryOperator *UnOp = dyn_cast(Arg)) { if (UnOp->getOpcode() == UnaryOperator::AddrOf) { DRE = dyn_cast(UnOp->getSubExpr()); if (DRE && !DRE->getQualifier()) DRE = 0; } - + } + // A constant of pointer-to-member type. + else if ((DRE = dyn_cast(Arg))) { + if (ValueDecl *VD = dyn_cast(DRE->getDecl())) { + if (VD->getType()->isMemberPointerType()) { + if (isa(VD) || + (isa(VD) && + Context.getCanonicalType(VD->getType()).isConstQualified())) { + if (Arg->isTypeDependent() || Arg->isValueDependent()) + Converted = TemplateArgument(Arg->Retain()); + else + Converted = TemplateArgument(VD->getCanonicalDecl()); + return Invalid; + } + } + } + + DRE = 0; + } + if (!DRE) return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_pointer_to_member_form) @@ -2139,7 +2158,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { // Okay: this is the address of a non-static member, and therefore // a member pointer constant. - Member = DRE->getDecl(); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + Converted = TemplateArgument(Arg->Retain()); + else + Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl()); return Invalid; } @@ -2343,16 +2365,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - if (ParamType->isMemberPointerType()) { - NamedDecl *Member = 0; - if (CheckTemplateArgumentPointerToMember(Arg, Member)) - return true; - - if (Member) - Member = cast(Member->getCanonicalDecl()); - Converted = TemplateArgument(Member); - return false; - } + if (ParamType->isMemberPointerType()) + return CheckTemplateArgumentPointerToMember(Arg, Converted); NamedDecl *Entity = 0; if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) @@ -2465,14 +2479,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - NamedDecl *Member = 0; - if (CheckTemplateArgumentPointerToMember(Arg, Member)) - return true; - - if (Member) - Member = cast(Member->getCanonicalDecl()); - Converted = TemplateArgument(Member); - return false; + return CheckTemplateArgumentPointerToMember(Arg, Converted); } /// \brief Check a template argument against its corresponding diff --git a/clang/test/SemaTemplate/instantiate-member-pointers.cpp b/clang/test/SemaTemplate/instantiate-member-pointers.cpp index 63e6dac096e1..826ea1e3eb5e 100644 --- a/clang/test/SemaTemplate/instantiate-member-pointers.cpp +++ b/clang/test/SemaTemplate/instantiate-member-pointers.cpp @@ -33,3 +33,16 @@ struct X3 { }; X3 x3; + +typedef int Y::*IntMember; + +template +struct X4 { + X3 member; + + int &getMember(Y& y) { return y.*Member; } +}; + +int &get_X4(X4<&Y::x> x4, Y& y) { + return x4.getMember(y); +} -- GitLab