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<
: 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,
/// 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.
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec,
ActionBase::TypeTy **Exceptions,
+ SourceRange *ExceptionRanges,
unsigned NumExceptions, SourceLocation Loc,
Declarator &TheDeclarator);
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);
//===--------------------------------------------------------------------===//
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.
bool hasExceptionSpec,
bool hasAnyExceptionSpec,
ActionBase::TypeTy **Exceptions,
+ SourceRange *ExceptionRanges,
unsigned NumExceptions,
SourceLocation Loc,
Declarator &TheDeclarator) {
}
// 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;
}
/// 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;
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())
// 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.");
}
}
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)) {
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*/);
// 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.");
}
}
DS.getTypeQualifiers(),
hasExceptionSpec,
hasAnyExceptionSpec,
- Exceptions.empty() ? 0 :
- &Exceptions[0],
+ Exceptions.data(),
+ ExceptionRanges.data(),
Exceptions.size(), LParenLoc, D),
Loc);
}
SourceLocation(),
&ParamInfo[0], ParamInfo.size(),
/*TypeQuals*/0,
- /*exception*/false, false, 0, 0,
+ /*exception*/false, false, 0, 0, 0,
LParenLoc, D),
RLoc);
}
/// 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");
}
// 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
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
SourceLocation(),
0, 0, 0,
- false, false, 0, 0,
+ false, false, 0, 0, 0,
CaretLoc, ParamInfo),
CaretLoc);
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);
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);
// 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"
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;
}
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.
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}}