зеркало из https://github.com/microsoft/clang-1.git
Reject incomplete types in exception specs.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72580 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
8ebefded18
Коммит
ef65f06e8e
|
@ -272,6 +272,9 @@ def err_deleted_decl_not_first : Error<
|
||||||
def err_distant_exception_spec : Error<
|
def err_distant_exception_spec : Error<
|
||||||
"exception specifications are not allowed beyond a single level "
|
"exception specifications are not allowed beyond a single level "
|
||||||
"of indirection">;
|
"of indirection">;
|
||||||
|
def err_incomplete_in_exception_spec : Error<
|
||||||
|
"%select{|pointer to |member pointer to |reference to }1incomplete type %0 "
|
||||||
|
"is not allowed in exception specification">;
|
||||||
|
|
||||||
// C++ access checking
|
// C++ access checking
|
||||||
def err_class_redeclared_with_different_access : Error<
|
def err_class_redeclared_with_different_access : Error<
|
||||||
|
|
|
@ -519,6 +519,11 @@ struct DeclaratorChunk {
|
||||||
DefaultArgTokens(DefArgTokens) {}
|
DefaultArgTokens(DefArgTokens) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TypeAndRange {
|
||||||
|
ActionBase::TypeTy *Ty;
|
||||||
|
SourceRange Range;
|
||||||
|
};
|
||||||
|
|
||||||
struct FunctionTypeInfo {
|
struct FunctionTypeInfo {
|
||||||
/// hasPrototype - This is true if the function had at least one typed
|
/// hasPrototype - This is true if the function had at least one typed
|
||||||
/// argument. If the function is () or (a,b,c), then it has no prototype,
|
/// argument. If the function is () or (a,b,c), then it has no prototype,
|
||||||
|
@ -559,9 +564,10 @@ struct DeclaratorChunk {
|
||||||
/// there are no arguments specified.
|
/// there are no arguments specified.
|
||||||
ParamInfo *ArgInfo;
|
ParamInfo *ArgInfo;
|
||||||
|
|
||||||
/// Exceptions - This is a pointer to a new[]'d array of TypeTy pointers
|
/// Exceptions - This is a pointer to a new[]'d array of TypeAndRange
|
||||||
/// that contains the types in the function's exception specification.
|
/// objects that contain the types in the function's exception
|
||||||
ActionBase::TypeTy **Exceptions;
|
/// specification and their locations.
|
||||||
|
TypeAndRange *Exceptions;
|
||||||
|
|
||||||
/// freeArgs - reset the argument list to having zero arguments. This is
|
/// freeArgs - reset the argument list to having zero arguments. This is
|
||||||
/// used in various places for error recovery.
|
/// used in various places for error recovery.
|
||||||
|
@ -700,6 +706,7 @@ struct DeclaratorChunk {
|
||||||
unsigned TypeQuals, bool hasExceptionSpec,
|
unsigned TypeQuals, bool hasExceptionSpec,
|
||||||
bool hasAnyExceptionSpec,
|
bool hasAnyExceptionSpec,
|
||||||
ActionBase::TypeTy **Exceptions,
|
ActionBase::TypeTy **Exceptions,
|
||||||
|
SourceRange *ExceptionRanges,
|
||||||
unsigned NumExceptions, SourceLocation Loc,
|
unsigned NumExceptions, SourceLocation Loc,
|
||||||
Declarator &TheDeclarator);
|
Declarator &TheDeclarator);
|
||||||
|
|
||||||
|
|
|
@ -772,7 +772,8 @@ private:
|
||||||
OwningExprResult ParseThrowExpression();
|
OwningExprResult ParseThrowExpression();
|
||||||
// EndLoc is filled with the location of the last token of the specification.
|
// EndLoc is filled with the location of the last token of the specification.
|
||||||
bool ParseExceptionSpecification(SourceLocation &EndLoc,
|
bool ParseExceptionSpecification(SourceLocation &EndLoc,
|
||||||
std::vector<TypeTy*> &Exceptions,
|
llvm::SmallVector<TypeTy*, 2> &Exceptions,
|
||||||
|
llvm::SmallVector<SourceRange, 2> &Ranges,
|
||||||
bool &hasAnyExceptionSpec);
|
bool &hasAnyExceptionSpec);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
|
@ -1057,7 +1058,7 @@ private:
|
||||||
TPResult TryParseFunctionDeclarator();
|
TPResult TryParseFunctionDeclarator();
|
||||||
TPResult TryParseBracketDeclarator();
|
TPResult TryParseBracketDeclarator();
|
||||||
|
|
||||||
TypeResult ParseTypeName();
|
TypeResult ParseTypeName(SourceRange *Range = 0);
|
||||||
void ParseBlockId();
|
void ParseBlockId();
|
||||||
// EndLoc, if non-NULL, is filled with the location of the last token of
|
// EndLoc, if non-NULL, is filled with the location of the last token of
|
||||||
// the attribute list.
|
// the attribute list.
|
||||||
|
|
|
@ -35,6 +35,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
|
||||||
bool hasExceptionSpec,
|
bool hasExceptionSpec,
|
||||||
bool hasAnyExceptionSpec,
|
bool hasAnyExceptionSpec,
|
||||||
ActionBase::TypeTy **Exceptions,
|
ActionBase::TypeTy **Exceptions,
|
||||||
|
SourceRange *ExceptionRanges,
|
||||||
unsigned NumExceptions,
|
unsigned NumExceptions,
|
||||||
SourceLocation Loc,
|
SourceLocation Loc,
|
||||||
Declarator &TheDeclarator) {
|
Declarator &TheDeclarator) {
|
||||||
|
@ -72,9 +73,11 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
|
||||||
}
|
}
|
||||||
// new[] an exception array if needed
|
// new[] an exception array if needed
|
||||||
if (NumExceptions) {
|
if (NumExceptions) {
|
||||||
I.Fun.Exceptions = new ActionBase::TypeTy*[NumExceptions];
|
I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
|
||||||
memcpy(I.Fun.Exceptions, Exceptions,
|
for (unsigned i = 0; i != NumExceptions; ++i) {
|
||||||
sizeof(ActionBase::TypeTy*)*NumExceptions);
|
I.Fun.Exceptions[i].Ty = Exceptions[i];
|
||||||
|
I.Fun.Exceptions[i].Range = ExceptionRanges[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return I;
|
return I;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ using namespace clang;
|
||||||
/// specifier-qualifier-list abstract-declarator[opt]
|
/// specifier-qualifier-list abstract-declarator[opt]
|
||||||
///
|
///
|
||||||
/// Called type-id in C++.
|
/// Called type-id in C++.
|
||||||
Action::TypeResult Parser::ParseTypeName() {
|
Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
|
||||||
// Parse the common declaration-specifiers piece.
|
// Parse the common declaration-specifiers piece.
|
||||||
DeclSpec DS;
|
DeclSpec DS;
|
||||||
ParseSpecifierQualifierList(DS);
|
ParseSpecifierQualifierList(DS);
|
||||||
|
@ -35,6 +35,8 @@ Action::TypeResult Parser::ParseTypeName() {
|
||||||
// Parse the abstract-declarator, if present.
|
// Parse the abstract-declarator, if present.
|
||||||
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
||||||
ParseDeclarator(DeclaratorInfo);
|
ParseDeclarator(DeclaratorInfo);
|
||||||
|
if (Range)
|
||||||
|
*Range = DeclaratorInfo.getSourceRange();
|
||||||
|
|
||||||
if (DeclaratorInfo.isInvalidType())
|
if (DeclaratorInfo.isInvalidType())
|
||||||
return true;
|
return true;
|
||||||
|
@ -2273,9 +2275,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
DeclSpec DS;
|
DeclSpec DS;
|
||||||
bool hasExceptionSpec = false;
|
bool hasExceptionSpec = false;
|
||||||
bool hasAnyExceptionSpec = false;
|
bool hasAnyExceptionSpec = false;
|
||||||
// FIXME: Does an empty vector ever allocate? Exception specifications are
|
llvm::SmallVector<TypeTy*, 2> Exceptions;
|
||||||
// extremely rare, so we want something like a SmallVector<TypeTy*, 0>. :-)
|
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
|
||||||
std::vector<TypeTy*> Exceptions;
|
|
||||||
if (getLang().CPlusPlus) {
|
if (getLang().CPlusPlus) {
|
||||||
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
||||||
if (!DS.getSourceRange().getEnd().isInvalid())
|
if (!DS.getSourceRange().getEnd().isInvalid())
|
||||||
|
@ -2284,7 +2285,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
// Parse exception-specification[opt].
|
// Parse exception-specification[opt].
|
||||||
if (Tok.is(tok::kw_throw)) {
|
if (Tok.is(tok::kw_throw)) {
|
||||||
hasExceptionSpec = true;
|
hasExceptionSpec = true;
|
||||||
ParseExceptionSpecification(Loc, Exceptions, hasAnyExceptionSpec);
|
ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
|
||||||
|
hasAnyExceptionSpec);
|
||||||
|
assert(Exceptions.size() == ExceptionRanges.size() &&
|
||||||
|
"Produced different number of exception types and ranges.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2297,8 +2301,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
DS.getTypeQualifiers(),
|
DS.getTypeQualifiers(),
|
||||||
hasExceptionSpec,
|
hasExceptionSpec,
|
||||||
hasAnyExceptionSpec,
|
hasAnyExceptionSpec,
|
||||||
Exceptions.empty() ? 0 :
|
Exceptions.data(),
|
||||||
&Exceptions[0],
|
ExceptionRanges.data(),
|
||||||
Exceptions.size(),
|
Exceptions.size(),
|
||||||
LParenLoc, D),
|
LParenLoc, D),
|
||||||
Loc);
|
Loc);
|
||||||
|
@ -2445,9 +2449,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
DeclSpec DS;
|
DeclSpec DS;
|
||||||
bool hasExceptionSpec = false;
|
bool hasExceptionSpec = false;
|
||||||
bool hasAnyExceptionSpec = false;
|
bool hasAnyExceptionSpec = false;
|
||||||
// FIXME: Does an empty vector ever allocate? Exception specifications are
|
llvm::SmallVector<TypeTy*, 2> Exceptions;
|
||||||
// extremely rare, so we want something like a SmallVector<TypeTy*, 0>. :-)
|
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
|
||||||
std::vector<TypeTy*> Exceptions;
|
|
||||||
if (getLang().CPlusPlus) {
|
if (getLang().CPlusPlus) {
|
||||||
// Parse cv-qualifier-seq[opt].
|
// Parse cv-qualifier-seq[opt].
|
||||||
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
||||||
|
@ -2457,7 +2460,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
// Parse exception-specification[opt].
|
// Parse exception-specification[opt].
|
||||||
if (Tok.is(tok::kw_throw)) {
|
if (Tok.is(tok::kw_throw)) {
|
||||||
hasExceptionSpec = true;
|
hasExceptionSpec = true;
|
||||||
ParseExceptionSpecification(Loc, Exceptions, hasAnyExceptionSpec);
|
ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
|
||||||
|
hasAnyExceptionSpec);
|
||||||
|
assert(Exceptions.size() == ExceptionRanges.size() &&
|
||||||
|
"Produced different number of exception types and ranges.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2468,8 +2474,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
DS.getTypeQualifiers(),
|
DS.getTypeQualifiers(),
|
||||||
hasExceptionSpec,
|
hasExceptionSpec,
|
||||||
hasAnyExceptionSpec,
|
hasAnyExceptionSpec,
|
||||||
Exceptions.empty() ? 0 :
|
Exceptions.data(),
|
||||||
&Exceptions[0],
|
ExceptionRanges.data(),
|
||||||
Exceptions.size(), LParenLoc, D),
|
Exceptions.size(), LParenLoc, D),
|
||||||
Loc);
|
Loc);
|
||||||
}
|
}
|
||||||
|
@ -2545,7 +2551,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
&ParamInfo[0], ParamInfo.size(),
|
&ParamInfo[0], ParamInfo.size(),
|
||||||
/*TypeQuals*/0,
|
/*TypeQuals*/0,
|
||||||
/*exception*/false, false, 0, 0,
|
/*exception*/false, false, 0, 0, 0,
|
||||||
LParenLoc, D),
|
LParenLoc, D),
|
||||||
RLoc);
|
RLoc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1191,7 +1191,10 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
|
||||||
/// type-id-list ',' type-id
|
/// type-id-list ',' type-id
|
||||||
///
|
///
|
||||||
bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
|
bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
|
||||||
std::vector<TypeTy*> &Exceptions,
|
llvm::SmallVector<TypeTy*, 2>
|
||||||
|
&Exceptions,
|
||||||
|
llvm::SmallVector<SourceRange, 2>
|
||||||
|
&Ranges,
|
||||||
bool &hasAnyExceptionSpec) {
|
bool &hasAnyExceptionSpec) {
|
||||||
assert(Tok.is(tok::kw_throw) && "expected throw");
|
assert(Tok.is(tok::kw_throw) && "expected throw");
|
||||||
|
|
||||||
|
@ -1214,10 +1217,13 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the sequence of type-ids.
|
// Parse the sequence of type-ids.
|
||||||
|
SourceRange Range;
|
||||||
while (Tok.isNot(tok::r_paren)) {
|
while (Tok.isNot(tok::r_paren)) {
|
||||||
TypeResult Res(ParseTypeName());
|
TypeResult Res(ParseTypeName(&Range));
|
||||||
if (!Res.isInvalid())
|
if (!Res.isInvalid()) {
|
||||||
Exceptions.push_back(Res.get());
|
Exceptions.push_back(Res.get());
|
||||||
|
Ranges.push_back(Range);
|
||||||
|
}
|
||||||
if (Tok.is(tok::comma))
|
if (Tok.is(tok::comma))
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
else
|
else
|
||||||
|
|
|
@ -1481,7 +1481,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
|
||||||
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
|
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
false, false, 0, 0,
|
false, false, 0, 0, 0,
|
||||||
CaretLoc, ParamInfo),
|
CaretLoc, ParamInfo),
|
||||||
CaretLoc);
|
CaretLoc);
|
||||||
|
|
||||||
|
|
|
@ -349,6 +349,7 @@ public:
|
||||||
QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
|
QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
|
||||||
TagDecl **OwnedDecl = 0);
|
TagDecl **OwnedDecl = 0);
|
||||||
DeclarationName GetNameForDeclarator(Declarator &D);
|
DeclarationName GetNameForDeclarator(Declarator &D);
|
||||||
|
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
|
||||||
bool CheckDistantExceptionSpec(QualType T);
|
bool CheckDistantExceptionSpec(QualType T);
|
||||||
|
|
||||||
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
|
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
|
||||||
|
|
|
@ -3176,7 +3176,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
|
||||||
assert(!Error && "Error setting up implicit decl!");
|
assert(!Error && "Error setting up implicit decl!");
|
||||||
Declarator D(DS, Declarator::BlockContext);
|
Declarator D(DS, Declarator::BlockContext);
|
||||||
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
|
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());
|
SourceLocation());
|
||||||
D.SetIdentifier(&II, Loc);
|
D.SetIdentifier(&II, Loc);
|
||||||
|
|
||||||
|
|
|
@ -760,13 +760,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
|
||||||
// function takes no arguments.
|
// function takes no arguments.
|
||||||
llvm::SmallVector<QualType, 4> Exceptions;
|
llvm::SmallVector<QualType, 4> Exceptions;
|
||||||
Exceptions.reserve(FTI.NumExceptions);
|
Exceptions.reserve(FTI.NumExceptions);
|
||||||
for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei)
|
for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
|
||||||
Exceptions.push_back(
|
QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
|
||||||
QualType::getFromOpaquePtr(FTI.Exceptions[ei]));
|
// 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,
|
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
|
||||||
FTI.hasExceptionSpec,
|
FTI.hasExceptionSpec,
|
||||||
FTI.hasAnyExceptionSpec,
|
FTI.hasAnyExceptionSpec,
|
||||||
FTI.NumExceptions, Exceptions.data());
|
Exceptions.size(), Exceptions.data());
|
||||||
} else if (FTI.isVariadic) {
|
} else if (FTI.isVariadic) {
|
||||||
// We allow a zero-parameter variadic function in C if the
|
// We allow a zero-parameter variadic function in C if the
|
||||||
// function is marked with the "overloadable"
|
// function is marked with the "overloadable"
|
||||||
|
@ -843,14 +847,19 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
|
||||||
|
|
||||||
llvm::SmallVector<QualType, 4> Exceptions;
|
llvm::SmallVector<QualType, 4> Exceptions;
|
||||||
Exceptions.reserve(FTI.NumExceptions);
|
Exceptions.reserve(FTI.NumExceptions);
|
||||||
for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei)
|
for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
|
||||||
Exceptions.push_back(QualType::getFromOpaquePtr(FTI.Exceptions[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(),
|
T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(),
|
||||||
FTI.isVariadic, FTI.TypeQuals,
|
FTI.isVariadic, FTI.TypeQuals,
|
||||||
FTI.hasExceptionSpec,
|
FTI.hasExceptionSpec,
|
||||||
FTI.hasAnyExceptionSpec,
|
FTI.hasAnyExceptionSpec,
|
||||||
FTI.NumExceptions, Exceptions.data());
|
Exceptions.size(), Exceptions.data());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -953,6 +962,43 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
|
||||||
return T;
|
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
|
/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
|
||||||
/// to member to a function with an exception specification. This means that
|
/// to member to a function with an exception specification. This means that
|
||||||
/// it is invalid to add another level of indirection.
|
/// it is invalid to add another level of indirection.
|
||||||
|
|
|
@ -23,3 +23,13 @@ void (**k)(void pfa() throw(int)); // no-error
|
||||||
void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
|
void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
|
||||||
// Pointer to function returning pointer to pointer to function with spec
|
// Pointer to function returning pointer to pointer to function with spec
|
||||||
void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
|
void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
|
||||||
|
|
||||||
|
struct Incomplete;
|
||||||
|
|
||||||
|
// Exception spec must not have incomplete types, or pointers to them, except
|
||||||
|
// void.
|
||||||
|
void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
|
||||||
|
void ic2() throw(Incomplete); // expected-error {{incomplete type 'struct Incomplete' is not allowed in exception specification}}
|
||||||
|
void ic3() throw(void*);
|
||||||
|
void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'struct Incomplete' is not allowed in exception specification}}
|
||||||
|
void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'struct Incomplete' is not allowed in exception specification}}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче