PR14388: An array or function type in an exception specification should be
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 28 Nov 2012 22:33:28 +0000 (22:33 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 28 Nov 2012 22:33:28 +0000 (22:33 +0000)
decayed to a pointer type. Patch by WenHan Gu, with a little tweaking and
additional testcases by me.

llvm-svn: 168822

clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaExceptionSpec.cpp
clang/test/CodeGenCXX/exception-spec-decay.cpp [new file with mode: 0644]
clang/test/SemaCXX/exceptions.cpp

index ee365c3..1e6ac18 100644 (file)
@@ -939,7 +939,7 @@ public:
   CanThrowResult canThrow(const Expr *E);
   const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
                                                 const FunctionProtoType *FPT);
-  bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
+  bool CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range);
   bool CheckDistantExceptionSpec(QualType T);
   bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
   bool CheckEquivalentExceptionSpec(
index e1f4888..8cb2cb4 100644 (file)
@@ -38,8 +38,10 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType 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) {
-
+///
+/// \param[in,out] T  The exception type. This will be decayed to a pointer type
+///                   when the input is an array or a function type.
+bool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) {
   // This check (and the similar one below) deals with issue 437, that changes
   // C++ 9.2p2 this way:
   // Within the class member-specification, the class is regarded as complete
@@ -47,33 +49,42 @@ bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
   // constructor ctor-initializers (including such things in nested classes).
   if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
     return false;
-    
+
+  // C++ 15.4p2: A type cv T, "array of T", or "function returning T" denoted
+  //   in an exception-specification is adjusted to type T, "pointer to T", or
+  //   "pointer to function returning T", respectively.
   // C++ 15.4p2: A type denoted in an exception-specification shall not denote
   //   an incomplete type.
-  if (RequireCompleteType(Range.getBegin(), T,
-                          diag::err_incomplete_in_exception_spec,
-                          /*direct*/0, Range))
+  if (T->isArrayType())
+    T = Context.getArrayDecayedType(T);
+  else if (T->isFunctionType())
+    T = Context.getPointerType(T);
+  else if (RequireCompleteType(Range.getBegin(), T,
+                               diag::err_incomplete_in_exception_spec,
+                               /*direct*/0, Range))
     return true;
 
+
   // 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*.
   int kind;
+  QualType PointeeT = T;
   if (const PointerType* IT = T->getAs<PointerType>()) {
-    T = IT->getPointeeType();
+    PointeeT = IT->getPointeeType();
     kind = 1;
   } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
-    T = IT->getPointeeType();
+    PointeeT = IT->getPointeeType();
     kind = 2;
   } else
     return false;
 
   // Again as before
-  if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
+  if (PointeeT->isRecordType() && PointeeT->getAs<RecordType>()->isBeingDefined())
     return false;
-    
-  if (!T->isVoidType() &&
-      RequireCompleteType(Range.getBegin(), T,
+
+  if (!PointeeT->isVoidType() &&
+      RequireCompleteType(Range.getBegin(), PointeeT,
                           diag::err_incomplete_in_exception_spec, kind, Range))
     return true;
 
diff --git a/clang/test/CodeGenCXX/exception-spec-decay.cpp b/clang/test/CodeGenCXX/exception-spec-decay.cpp
new file mode 100644 (file)
index 0000000..4928353
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions %s -triple=i686-unknown-linux -emit-llvm -o - | FileCheck %s
+typedef int Array[10];
+
+void foo() throw (Array) {
+  throw 0;
+  // CHECK: landingpad
+  // CHECK-NEXT: filter {{.*}} @_ZTIPi
+}
+
+struct S {
+  void foo() throw (S[10]) {
+    throw 0;
+  }
+};
+
+template <typename T>
+struct S2 {
+  void foo() throw (T) {
+    throw 0;
+  }
+};
+
+int main() {
+  S s;
+  s.foo();
+  // CHECK: landingpad
+  // CHECK-NEXT: filter {{.*}} @_ZTIP1S
+
+  S2 <int[10]> s2;
+  s2.foo();
+  // CHECK: landingpad
+  // CHECK-NEXT: filter {{.*}} @_ZTIPi
+}
index 486d88e..8e32494 100644 (file)
@@ -120,3 +120,26 @@ namespace PR6831 {
     }
   }
 }
+
+namespace Decay {
+  struct A {
+    void f() throw (A[10]);
+  };
+
+  template<typename T> struct B {
+    void f() throw (B[10]);
+  };
+  template struct B<int>;
+
+  void f() throw (int[10], int(*)());
+  void f() throw (int*, int());
+
+  template<typename T> struct C {
+    void f() throw (T); // expected-error {{pointer to incomplete type 'Decay::E' is not allowed in exception specification}}
+  };
+  struct D {
+    C<D[10]> c;
+  };
+  struct E; // expected-note {{forward declaration}}
+  C<E[10]> e; // expected-note {{in instantiation of}}
+}