зеркало из 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<
|
||||
"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<
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче