зеркало из https://github.com/microsoft/clang.git
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
This commit is contained in:
Родитель
060f34d6d1
Коммит
21173b1080
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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}}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче