Make sure to use RequireCompleteType rather than testing for
incomplete types. RequireCompleteType is needed when the type may be
completed by instantiating a template.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67643 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2732a54..03d8501 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1593,14 +1593,20 @@
     return ExprError(Diag(IndexExpr->getLocStart(),
       diag::err_typecheck_subscript) << IndexExpr->getSourceRange());
 
-  // C99 6.5.2.1p1: "shall have type "pointer to *object* type".  In practice,
-  // the following check catches trying to index a pointer to a function (e.g.
-  // void (*)(int)) and pointers to incomplete types.  Functions are not
-  // objects in C99.
-  if (!ResultType->isObjectType() && !ResultType->isDependentType())
-    return ExprError(Diag(BaseExpr->getLocStart(),
-                diag::err_typecheck_subscript_not_object)
-      << BaseExpr->getType() << BaseExpr->getSourceRange());
+  // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
+  // C++ [expr.sub]p1: The type "T" shall be a completely-defined object 
+  // type. Note that Functions are not objects, and that (in C99 parlance) 
+  // incomplete types are not object types.
+  if (ResultType->isFunctionType()) {
+    Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type)
+      << ResultType << BaseExpr->getSourceRange();
+    return ExprError();
+  }
+  if (!ResultType->isDependentType() &&
+      RequireCompleteType(BaseExpr->getLocStart(), ResultType, 
+                          diag::err_subscript_incomplete_type,
+                          BaseExpr->getSourceRange()))
+    return ExprError();
 
   Base.release();
   Idx.release();
@@ -3155,35 +3161,33 @@
   if (const PointerType* PTy = PExp->getType()->getAsPointerType()) {
     if (IExp->getType()->isIntegerType()) {
       // Check for arithmetic on pointers to incomplete types
-      if (!PTy->getPointeeType()->isObjectType()) {
-        if (PTy->getPointeeType()->isVoidType()) {
-          if (getLangOptions().CPlusPlus) {
-            Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
-              << lex->getSourceRange() << rex->getSourceRange();
-            return QualType();
-          }
-
-          // GNU extension: arithmetic on pointer to void
-          Diag(Loc, diag::ext_gnu_void_ptr)
+      if (PTy->getPointeeType()->isVoidType()) {
+        if (getLangOptions().CPlusPlus) {
+          Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
             << lex->getSourceRange() << rex->getSourceRange();
-        } else if (PTy->getPointeeType()->isFunctionType()) {
-          if (getLangOptions().CPlusPlus) {
-            Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
-              << lex->getType() << lex->getSourceRange();
-            return QualType();
-          }
-
-          // GNU extension: arithmetic on pointer to function
-          Diag(Loc, diag::ext_gnu_ptr_func_arith)
-            << lex->getType() << lex->getSourceRange();
-        } else {
-          RequireCompleteType(Loc, PTy->getPointeeType(),
-                                 diag::err_typecheck_arithmetic_incomplete_type,
-                                 lex->getSourceRange(), SourceRange(),
-                                 lex->getType());
           return QualType();
         }
-      }
+
+        // GNU extension: arithmetic on pointer to void
+        Diag(Loc, diag::ext_gnu_void_ptr)
+          << lex->getSourceRange() << rex->getSourceRange();
+      } else if (PTy->getPointeeType()->isFunctionType()) {
+        if (getLangOptions().CPlusPlus) {
+          Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
+            << lex->getType() << lex->getSourceRange();
+          return QualType();
+        }
+
+        // GNU extension: arithmetic on pointer to function
+        Diag(Loc, diag::ext_gnu_ptr_func_arith)
+          << lex->getType() << lex->getSourceRange();
+      } else if (!PTy->isDependentType() &&
+                 RequireCompleteType(Loc, PTy->getPointeeType(),
+                                diag::err_typecheck_arithmetic_incomplete_type,
+                                     lex->getSourceRange(), SourceRange(),
+                                     lex->getType()))
+        return QualType();
+
       return PExp->getType();
     }
   }
@@ -3209,61 +3213,80 @@
   if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
     QualType lpointee = LHSPTy->getPointeeType();
 
-    // The LHS must be an object type, not incomplete, function, etc.
-    if (!lpointee->isObjectType()) {
-      // Handle the GNU void* extension.
-      if (lpointee->isVoidType()) {
-        Diag(Loc, diag::ext_gnu_void_ptr)
-          << lex->getSourceRange() << rex->getSourceRange();
-      } else if (lpointee->isFunctionType()) {
-        if (getLangOptions().CPlusPlus) {
-          Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
-            << lex->getType() << lex->getSourceRange();
-          return QualType();
-        }
+    // The LHS must be an completely-defined object type.
 
-        // GNU extension: arithmetic on pointer to function
-        Diag(Loc, diag::ext_gnu_ptr_func_arith)
-          << lex->getType() << lex->getSourceRange();
-      } else {
-        Diag(Loc, diag::err_typecheck_sub_ptr_object)
+    bool ComplainAboutVoid = false;
+    Expr *ComplainAboutFunc = 0;
+    if (lpointee->isVoidType()) {
+      if (getLangOptions().CPlusPlus) {
+        Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
+          << lex->getSourceRange() << rex->getSourceRange();
+        return QualType();
+      }
+
+      // GNU C extension: arithmetic on pointer to void
+      ComplainAboutVoid = true;
+    } else if (lpointee->isFunctionType()) {
+      if (getLangOptions().CPlusPlus) {
+        Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
           << lex->getType() << lex->getSourceRange();
         return QualType();
       }
-    }
+
+      // GNU C extension: arithmetic on pointer to function
+      ComplainAboutFunc = lex;
+    } else if (!lpointee->isDependentType() &&
+               RequireCompleteType(Loc, lpointee, 
+                                   diag::err_typecheck_sub_ptr_object,
+                                   lex->getSourceRange(),
+                                   SourceRange(),
+                                   lex->getType()))
+      return QualType();
 
     // The result type of a pointer-int computation is the pointer type.
-    if (rex->getType()->isIntegerType())
+    if (rex->getType()->isIntegerType()) {
+      if (ComplainAboutVoid)
+        Diag(Loc, diag::ext_gnu_void_ptr)
+          << lex->getSourceRange() << rex->getSourceRange();
+      if (ComplainAboutFunc)
+        Diag(Loc, diag::ext_gnu_ptr_func_arith)
+          << ComplainAboutFunc->getType() 
+          << ComplainAboutFunc->getSourceRange();
+
       return lex->getType();
+    }
 
     // Handle pointer-pointer subtractions.
     if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
       QualType rpointee = RHSPTy->getPointeeType();
 
-      // RHS must be an object type, unless void (GNU).
-      if (!rpointee->isObjectType()) {
-        // Handle the GNU void* extension.
-        if (rpointee->isVoidType()) {
-          if (!lpointee->isVoidType())
-            Diag(Loc, diag::ext_gnu_void_ptr)
-              << lex->getSourceRange() << rex->getSourceRange();
-        } else if (rpointee->isFunctionType()) {
-          if (getLangOptions().CPlusPlus) {
-            Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
-              << rex->getType() << rex->getSourceRange();
-            return QualType();
-          }
+      // RHS must be a completely-type object type.
+      // Handle the GNU void* extension.
+      if (rpointee->isVoidType()) {
+        if (getLangOptions().CPlusPlus) {
+          Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
+            << lex->getSourceRange() << rex->getSourceRange();
+          return QualType();
+        }
 
-          // GNU extension: arithmetic on pointer to function
-          if (!lpointee->isFunctionType())
-            Diag(Loc, diag::ext_gnu_ptr_func_arith)
-              << lex->getType() << lex->getSourceRange();
-        } else {
-          Diag(Loc, diag::err_typecheck_sub_ptr_object)
+        ComplainAboutVoid = true;
+      } else if (rpointee->isFunctionType()) {
+        if (getLangOptions().CPlusPlus) {
+          Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
             << rex->getType() << rex->getSourceRange();
           return QualType();
         }
-      }
+
+        // GNU extension: arithmetic on pointer to function
+        if (!ComplainAboutFunc)
+          ComplainAboutFunc = rex;
+      } else if (!rpointee->isDependentType() &&
+                 RequireCompleteType(Loc, rpointee,
+                                     diag::err_typecheck_sub_ptr_object,
+                                     rex->getSourceRange(),
+                                     SourceRange(),
+                                     rex->getType()))
+        return QualType();
 
       // Pointee types must be compatible.
       if (!Context.typesAreCompatible(
@@ -3275,6 +3298,14 @@
         return QualType();
       }
 
+      if (ComplainAboutVoid)
+        Diag(Loc, diag::ext_gnu_void_ptr)
+          << lex->getSourceRange() << rex->getSourceRange();
+      if (ComplainAboutFunc)
+        Diag(Loc, diag::ext_gnu_ptr_func_arith)
+          << ComplainAboutFunc->getType() 
+          << ComplainAboutFunc->getSourceRange();
+        
       return Context.getPointerDiffType();
     }
   }