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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@87010 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 2557dfe..4a6d01b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2615,7 +2615,8 @@
                              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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index af7634a..07d7839 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1187,11 +1187,10 @@
 
   QualType CanonType;
 
-  if (TemplateSpecializationType::anyDependentTemplateArguments(
+  if (Name.isDependent() ||
+      TemplateSpecializationType::anyDependentTemplateArguments(
                                                       TemplateArgs,
-                                                      NumTemplateArgs) ||
-      isa<TemplateTemplateParmDecl>(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 @@
 
 /// \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 @@
     Arg = Parens->getSubExpr();
   }
 
-  if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg))
+  // A pointer-to-member constant written &Class::member.
+  if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
     if (UnOp->getOpcode() == UnaryOperator::AddrOf) {
       DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
       if (DRE && !DRE->getQualifier())
         DRE = 0;
     }
-
+  } 
+  // A constant of pointer-to-member type.
+  else if ((DRE = dyn_cast<DeclRefExpr>(Arg))) {
+    if (ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) {
+      if (VD->getType()->isMemberPointerType()) {
+        if (isa<NonTypeTemplateParmDecl>(VD) ||
+            (isa<VarDecl>(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 @@
 
     // 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 @@
       return true;
     }
 
-    if (ParamType->isMemberPointerType()) {
-      NamedDecl *Member = 0;
-      if (CheckTemplateArgumentPointerToMember(Arg, Member))
-        return true;
-
-      if (Member)
-        Member = cast<NamedDecl>(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 @@
     return true;
   }
 
-  NamedDecl *Member = 0;
-  if (CheckTemplateArgumentPointerToMember(Arg, Member))
-    return true;
-
-  if (Member)
-    Member = cast<NamedDecl>(Member->getCanonicalDecl());
-  Converted = TemplateArgument(Member);
-  return false;
+  return CheckTemplateArgumentPointerToMember(Arg, Converted);
 }
 
 /// \brief Check a template argument against its corresponding
diff --git a/test/SemaTemplate/instantiate-member-pointers.cpp b/test/SemaTemplate/instantiate-member-pointers.cpp
index 63e6dac..826ea1e 100644
--- a/test/SemaTemplate/instantiate-member-pointers.cpp
+++ b/test/SemaTemplate/instantiate-member-pointers.cpp
@@ -33,3 +33,16 @@
 };
 
 X3<int, Y, &Y::x> x3;
+
+typedef int Y::*IntMember;
+
+template<IntMember Member>
+struct X4 {
+  X3<int, Y, Member> member;
+  
+  int &getMember(Y& y) { return y.*Member; }
+};
+
+int &get_X4(X4<&Y::x> x4, Y& y) { 
+  return x4.getMember(y); 
+}