Reject incomplete types in exception specs.

llvm-svn: 72580
This commit is contained in:
Sebastian Redl 2009-05-29 18:02:33 +00:00
parent 9d809cad50
commit d643456d45
11 changed files with 122 additions and 39 deletions

View File

@ -272,6 +272,9 @@ def err_deleted_decl_not_first : Error<
def err_distant_exception_spec : Error<
"exception specifications are not allowed beyond a single level "
"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
def err_class_redeclared_with_different_access : Error<

View File

@ -518,7 +518,12 @@ struct DeclaratorChunk {
: Ident(ident), IdentLoc(iloc), Param(param),
DefaultArgTokens(DefArgTokens) {}
};
struct TypeAndRange {
ActionBase::TypeTy *Ty;
SourceRange Range;
};
struct FunctionTypeInfo {
/// 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,
@ -559,9 +564,10 @@ struct DeclaratorChunk {
/// there are no arguments specified.
ParamInfo *ArgInfo;
/// Exceptions - This is a pointer to a new[]'d array of TypeTy pointers
/// that contains the types in the function's exception specification.
ActionBase::TypeTy **Exceptions;
/// Exceptions - This is a pointer to a new[]'d array of TypeAndRange
/// objects that contain the types in the function's exception
/// specification and their locations.
TypeAndRange *Exceptions;
/// freeArgs - reset the argument list to having zero arguments. This is
/// used in various places for error recovery.
@ -700,6 +706,7 @@ struct DeclaratorChunk {
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec,
ActionBase::TypeTy **Exceptions,
SourceRange *ExceptionRanges,
unsigned NumExceptions, SourceLocation Loc,
Declarator &TheDeclarator);

View File

@ -772,7 +772,8 @@ private:
OwningExprResult ParseThrowExpression();
// EndLoc is filled with the location of the last token of the specification.
bool ParseExceptionSpecification(SourceLocation &EndLoc,
std::vector<TypeTy*> &Exceptions,
llvm::SmallVector<TypeTy*, 2> &Exceptions,
llvm::SmallVector<SourceRange, 2> &Ranges,
bool &hasAnyExceptionSpec);
//===--------------------------------------------------------------------===//
@ -1057,7 +1058,7 @@ private:
TPResult TryParseFunctionDeclarator();
TPResult TryParseBracketDeclarator();
TypeResult ParseTypeName();
TypeResult ParseTypeName(SourceRange *Range = 0);
void ParseBlockId();
// EndLoc, if non-NULL, is filled with the location of the last token of
// the attribute list.

View File

@ -35,6 +35,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
bool hasExceptionSpec,
bool hasAnyExceptionSpec,
ActionBase::TypeTy **Exceptions,
SourceRange *ExceptionRanges,
unsigned NumExceptions,
SourceLocation Loc,
Declarator &TheDeclarator) {
@ -72,9 +73,11 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
}
// new[] an exception array if needed
if (NumExceptions) {
I.Fun.Exceptions = new ActionBase::TypeTy*[NumExceptions];
memcpy(I.Fun.Exceptions, Exceptions,
sizeof(ActionBase::TypeTy*)*NumExceptions);
I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
for (unsigned i = 0; i != NumExceptions; ++i) {
I.Fun.Exceptions[i].Ty = Exceptions[i];
I.Fun.Exceptions[i].Range = ExceptionRanges[i];
}
}
return I;
}

View File

@ -27,15 +27,17 @@ using namespace clang;
/// specifier-qualifier-list abstract-declarator[opt]
///
/// Called type-id in C++.
Action::TypeResult Parser::ParseTypeName() {
Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
// Parse the common declaration-specifiers piece.
DeclSpec DS;
ParseSpecifierQualifierList(DS);
// Parse the abstract-declarator, if present.
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
ParseDeclarator(DeclaratorInfo);
if (Range)
*Range = DeclaratorInfo.getSourceRange();
if (DeclaratorInfo.isInvalidType())
return true;
@ -2273,9 +2275,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DeclSpec DS;
bool hasExceptionSpec = false;
bool hasAnyExceptionSpec = false;
// FIXME: Does an empty vector ever allocate? Exception specifications are
// extremely rare, so we want something like a SmallVector<TypeTy*, 0>. :-)
std::vector<TypeTy*> Exceptions;
llvm::SmallVector<TypeTy*, 2> Exceptions;
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
if (getLang().CPlusPlus) {
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
if (!DS.getSourceRange().getEnd().isInvalid())
@ -2284,7 +2285,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse exception-specification[opt].
if (Tok.is(tok::kw_throw)) {
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,14 +2301,14 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DS.getTypeQualifiers(),
hasExceptionSpec,
hasAnyExceptionSpec,
Exceptions.empty() ? 0 :
&Exceptions[0],
Exceptions.data(),
ExceptionRanges.data(),
Exceptions.size(),
LParenLoc, D),
Loc);
return;
}
}
// Alternatively, this parameter list may be an identifier list form for a
// K&R-style function: void foo(a,b,c)
if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
@ -2445,9 +2449,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DeclSpec DS;
bool hasExceptionSpec = false;
bool hasAnyExceptionSpec = false;
// FIXME: Does an empty vector ever allocate? Exception specifications are
// extremely rare, so we want something like a SmallVector<TypeTy*, 0>. :-)
std::vector<TypeTy*> Exceptions;
llvm::SmallVector<TypeTy*, 2> Exceptions;
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
if (getLang().CPlusPlus) {
// Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
@ -2457,7 +2460,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse exception-specification[opt].
if (Tok.is(tok::kw_throw)) {
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(),
hasExceptionSpec,
hasAnyExceptionSpec,
Exceptions.empty() ? 0 :
&Exceptions[0],
Exceptions.data(),
ExceptionRanges.data(),
Exceptions.size(), LParenLoc, D),
Loc);
}
@ -2545,7 +2551,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
SourceLocation(),
&ParamInfo[0], ParamInfo.size(),
/*TypeQuals*/0,
/*exception*/false, false, 0, 0,
/*exception*/false, false, 0, 0, 0,
LParenLoc, D),
RLoc);
}

View File

@ -1191,7 +1191,10 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
/// type-id-list ',' type-id
///
bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
std::vector<TypeTy*> &Exceptions,
llvm::SmallVector<TypeTy*, 2>
&Exceptions,
llvm::SmallVector<SourceRange, 2>
&Ranges,
bool &hasAnyExceptionSpec) {
assert(Tok.is(tok::kw_throw) && "expected throw");
@ -1214,10 +1217,13 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
}
// Parse the sequence of type-ids.
SourceRange Range;
while (Tok.isNot(tok::r_paren)) {
TypeResult Res(ParseTypeName());
if (!Res.isInvalid())
TypeResult Res(ParseTypeName(&Range));
if (!Res.isInvalid()) {
Exceptions.push_back(Res.get());
Ranges.push_back(Range);
}
if (Tok.is(tok::comma))
ConsumeToken();
else

View File

@ -1481,7 +1481,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
SourceLocation(),
0, 0, 0,
false, false, 0, 0,
false, false, 0, 0, 0,
CaretLoc, ParamInfo),
CaretLoc);

View File

@ -349,6 +349,7 @@ public:
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);

View File

@ -3176,7 +3176,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
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);

View File

@ -760,13 +760,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// 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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
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.

View File

@ -23,3 +23,13 @@ void (**k)(void pfa() throw(int)); // no-error
void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
// Pointer to function returning pointer to pointer to function with spec
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}}