Reject incomplete types in exception specs.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72580 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 6559ca4..6214eb5 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -349,6 +349,7 @@
   QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
                                 TagDecl **OwnedDecl = 0);
   DeclarationName GetNameForDeclarator(Declarator &D);
+  bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
   bool CheckDistantExceptionSpec(QualType T);
 
   QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index abae9f0..8375a68 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3176,7 +3176,7 @@
   assert(!Error && "Error setting up implicit decl!");
   Declarator D(DS, Declarator::BlockContext);
   D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
-                                             0, 0, false, false, 0, 0, Loc, D),
+                                             0, 0, false, false, 0,0,0, Loc, D),
                 SourceLocation());
   D.SetIdentifier(&II, Loc);
 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 01b8aa4..833620b 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -760,13 +760,17 @@
           // function takes no arguments.
           llvm::SmallVector<QualType, 4> Exceptions;
           Exceptions.reserve(FTI.NumExceptions);
-          for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei)
-            Exceptions.push_back(
-              QualType::getFromOpaquePtr(FTI.Exceptions[ei]));
+          for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+            QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+            // Check that the type is valid for an exception spec, and drop it
+            // if not.
+            if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+              Exceptions.push_back(ET);
+          }
           T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
                                       FTI.hasExceptionSpec,
                                       FTI.hasAnyExceptionSpec,
-                                      FTI.NumExceptions, Exceptions.data());
+                                      Exceptions.size(), Exceptions.data());
         } else if (FTI.isVariadic) {
           // We allow a zero-parameter variadic function in C if the
           // function is marked with the "overloadable"
@@ -843,14 +847,19 @@
 
         llvm::SmallVector<QualType, 4> Exceptions;
         Exceptions.reserve(FTI.NumExceptions);
-        for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei)
-          Exceptions.push_back(QualType::getFromOpaquePtr(FTI.Exceptions[ei]));
+        for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+          QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+          // Check that the type is valid for an exception spec, and drop it if
+          // not.
+          if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+            Exceptions.push_back(ET);
+        }
 
         T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(),
                                     FTI.isVariadic, FTI.TypeQuals,
                                     FTI.hasExceptionSpec,
                                     FTI.hasAnyExceptionSpec,
-                                    FTI.NumExceptions, Exceptions.data());
+                                    Exceptions.size(), Exceptions.data());
       }
       break;
     }
@@ -953,6 +962,43 @@
   return T;
 }
 
+/// CheckSpecifiedExceptionType - Check if the given type is valid in an
+/// exception specification. Incomplete types, or pointers to incomplete types
+/// other than void are not allowed.
+bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
+  // FIXME: This may not correctly work with the fix for core issue 437,
+  // where a class's own type is considered complete within its body.
+
+  // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+  //   an incomplete type.
+  if (T->isIncompleteType())
+    return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
+      << Range << T << /*direct*/0;
+
+  // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+  //   an incomplete type a pointer or reference to an incomplete type, other
+  //   than (cv) void*.
+  // The standard does not mention member pointers, but it has to mean them too.
+  int kind;
+  if (const PointerType* IT = T->getAsPointerType()) {
+    T = IT->getPointeeType();
+    kind = 1;
+  } else if (const MemberPointerType* IT = T->getAsMemberPointerType()) {
+    T = IT->getPointeeType();
+    kind = 2;
+  } else if (const ReferenceType* IT = T->getAsReferenceType()) {
+    T = IT->getPointeeType();
+    kind = 3;
+  } else
+    return false;
+
+  if (T->isIncompleteType() && !T->isVoidType())
+    return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
+      << Range << T << /*indirect*/kind;
+
+  return false;
+}
+
 /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
 /// to member to a function with an exception specification. This means that
 /// it is invalid to add another level of indirection.