Handle member pointer types with dependent class types (e.g., int
T::*) and implement template instantiation for member pointer types.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73151 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index cd19d97..6c2a4dc 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -600,7 +600,67 @@
   return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, 
                                  Quals);
 }
-                                 
+ 
+/// \brief Build a member pointer type \c T Class::*.
+///
+/// \param T the type to which the member pointer refers.
+/// \param Class the class type into which the member pointer points.
+/// \param Quals Qualifiers applied to the member pointer type
+/// \param Loc the location where this type begins
+/// \param Entity the name of the entity that will have this member pointer type
+///
+/// \returns a member pointer type, if successful, or a NULL type if there was
+/// an error.
+QualType Sema::BuildMemberPointerType(QualType T, QualType Class, 
+                                      unsigned Quals, SourceLocation Loc, 
+                                      DeclarationName Entity) {
+  // Verify that we're not building a pointer to pointer to function with
+  // exception specification.
+  if (CheckDistantExceptionSpec(T)) {
+    Diag(Loc, diag::err_distant_exception_spec);
+
+    // FIXME: If we're doing this as part of template instantiation,
+    // we should return immediately.
+
+    // Build the type anyway, but use the canonical type so that the
+    // exception specifiers are stripped off.
+    T = Context.getCanonicalType(T);
+  }
+
+  // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
+  //   with reference type, or "cv void."
+  if (T->isReferenceType()) {
+    Diag(Loc, diag::err_illegal_decl_pointer_to_reference)
+      << (Entity? Entity.getAsString() : "type name");
+    return QualType();
+  }
+
+  if (T->isVoidType()) {
+    Diag(Loc, diag::err_illegal_decl_mempointer_to_void)
+      << (Entity? Entity.getAsString() : "type name");
+    return QualType();
+  }
+
+  // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+  // object or incomplete types shall not be restrict-qualified."
+  if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+    Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+      << T;
+
+    // FIXME: If we're doing this as part of template instantiation,
+    // we should return immediately.
+    Quals &= ~QualType::Restrict;
+  }
+
+  if (!Class->isDependentType() && !Class->isRecordType()) {
+    Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class;
+    return QualType();
+  }
+
+  return Context.getMemberPointerType(T, Class.getTypePtr())
+           .getQualifiedType(Quals);  
+}
+                              
 /// GetTypeForDeclarator - Convert the type for the specified
 /// declarator to Type instances. Skip the outermost Skip type
 /// objects.
@@ -870,57 +930,32 @@
       break;
     }
     case DeclaratorChunk::MemberPointer:
-      // Verify that we're not building a pointer to pointer to function with
-      // exception specification.
-      if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
-        Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
-        D.setInvalidType(true);
-        // Build the type anyway.
-      }
       // The scope spec must refer to a class, or be dependent.
-      DeclContext *DC = computeDeclContext(DeclType.Mem.Scope());
       QualType ClsType;
-      // FIXME: Extend for dependent types when it's actually supported.
-      // See ActOnCXXNestedNameSpecifier.
-      if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) {
+      if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
+        NestedNameSpecifier *NNS 
+          = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
+        assert(NNS->getAsType() && "Nested-name-specifier must name a type");
+        ClsType = QualType(NNS->getAsType(), 0);
+      } else if (CXXRecordDecl *RD 
+                   = dyn_cast_or_null<CXXRecordDecl>(
+                                    computeDeclContext(DeclType.Mem.Scope()))) {
         ClsType = Context.getTagDeclType(RD);
       } else {
-        if (DC) {
-          Diag(DeclType.Mem.Scope().getBeginLoc(),
-               diag::err_illegal_decl_mempointer_in_nonclass)
-            << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
-            << DeclType.Mem.Scope().getRange();
-        }
+        Diag(DeclType.Mem.Scope().getBeginLoc(),
+             diag::err_illegal_decl_mempointer_in_nonclass)
+          << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
+          << DeclType.Mem.Scope().getRange();
         D.setInvalidType(true);
-        ClsType = Context.IntTy;
       }
 
-      // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
-      //   with reference type, or "cv void."
-      if (T->isReferenceType()) {
-        Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference)
-          << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+      if (!ClsType.isNull())
+        T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
+                                   DeclType.Loc, D.getIdentifier());
+      if (T.isNull()) {
+        T = Context.IntTy;
         D.setInvalidType(true);
-        T = Context.IntTy;
       }
-      if (T->isVoidType()) {
-        Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void)
-          << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
-        T = Context.IntTy;
-      }
-
-      // Enforce C99 6.7.3p2: "Types other than pointer types derived from
-      // object or incomplete types shall not be restrict-qualified."
-      if ((DeclType.Mem.TypeQuals & QualType::Restrict) &&
-          !T->isIncompleteOrObjectType()) {
-        Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
-          << T;
-        DeclType.Mem.TypeQuals &= ~QualType::Restrict;
-      }
-
-      T = Context.getMemberPointerType(T, ClsType.getTypePtr()).
-                    getQualifiedType(DeclType.Mem.TypeQuals);
-
       break;
     }