From 21173b1080abaa2738f9e700a9d4b0d04f928930 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Nov 2012 22:33:28 +0000 Subject: [PATCH] PR14388: An array or function type in an exception specification should be decayed to a pointer type. Patch by WenHan Gu, with a little tweaking and additional testcases by me. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168822 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 2 +- lib/Sema/SemaExceptionSpec.cpp | 35 ++++++++++++++++-------- test/CodeGenCXX/exception-spec-decay.cpp | 33 ++++++++++++++++++++++ test/SemaCXX/exceptions.cpp | 23 ++++++++++++++++ 4 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 test/CodeGenCXX/exception-spec-decay.cpp diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ee365c3299..1e6ac187dc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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( diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index e1f4888d63..8cb2cb4290 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -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()->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()) { - T = IT->getPointeeType(); + PointeeT = IT->getPointeeType(); kind = 1; } else if (const ReferenceType* IT = T->getAs()) { - T = IT->getPointeeType(); + PointeeT = IT->getPointeeType(); kind = 2; } else return false; // Again as before - if (T->isRecordType() && T->getAs()->isBeingDefined()) + if (PointeeT->isRecordType() && PointeeT->getAs()->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/test/CodeGenCXX/exception-spec-decay.cpp b/test/CodeGenCXX/exception-spec-decay.cpp new file mode 100644 index 0000000000..4928353907 --- /dev/null +++ b/test/CodeGenCXX/exception-spec-decay.cpp @@ -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 +struct S2 { + void foo() throw (T) { + throw 0; + } +}; + +int main() { + S s; + s.foo(); + // CHECK: landingpad + // CHECK-NEXT: filter {{.*}} @_ZTIP1S + + S2 s2; + s2.foo(); + // CHECK: landingpad + // CHECK-NEXT: filter {{.*}} @_ZTIPi +} diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp index 486d88eab7..8e32494825 100644 --- a/test/SemaCXX/exceptions.cpp +++ b/test/SemaCXX/exceptions.cpp @@ -120,3 +120,26 @@ namespace PR6831 { } } } + +namespace Decay { + struct A { + void f() throw (A[10]); + }; + + template struct B { + void f() throw (B[10]); + }; + template struct B; + + void f() throw (int[10], int(*)()); + void f() throw (int*, int()); + + template struct C { + void f() throw (T); // expected-error {{pointer to incomplete type 'Decay::E' is not allowed in exception specification}} + }; + struct D { + C c; + }; + struct E; // expected-note {{forward declaration}} + C e; // expected-note {{in instantiation of}} +} -- 2.40.0