Reintroduce the home for exception specs, and make Sema fill it. However, keep the spec out of the canonical type this time. Net effect is currently nothing, because the spec isn't checked anywhere.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72498 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sebastian Redl 2009-05-27 22:11:52 +00:00
Родитель cfcceab862
Коммит 465226e23a
9 изменённых файлов: 128 добавлений и 31 удалений

Просмотреть файл

@ -287,12 +287,14 @@ public:
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
/// ///
QualType getFunctionNoProtoType(QualType ResultTy); QualType getFunctionNoProtoType(QualType ResultTy);
/// getFunctionType - Return a normal function type with a typed argument /// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'. /// list. isVariadic indicates whether the argument list includes '...'.
QualType getFunctionType(QualType ResultTy, const QualType *ArgArray, QualType getFunctionType(QualType ResultTy, const QualType *ArgArray,
unsigned NumArgs, bool isVariadic, unsigned NumArgs, bool isVariadic,
unsigned TypeQuals); unsigned TypeQuals, bool hasExceptionSpec = false,
bool hasAnyExceptionSpec = false,
unsigned NumExs = 0, const QualType *ExArray = 0);
/// getTypeDeclType - Return the unique reference to the type for /// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration. /// the specified type declaration.

Просмотреть файл

@ -1151,7 +1151,9 @@ public:
/// FunctionProtoType - Represents a prototype with argument type info, e.g. /// FunctionProtoType - Represents a prototype with argument type info, e.g.
/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
/// arguments, not as having a single void argument. /// arguments, not as having a single void argument. Such a type can have an
/// exception specification, but this specification is not part of the canonical
/// type.
class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
/// hasAnyDependentType - Determine whether there are any dependent /// hasAnyDependentType - Determine whether there are any dependent
/// types within the arguments passed in. /// types within the arguments passed in.
@ -1164,23 +1166,42 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
} }
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs, FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
bool isVariadic, unsigned typeQuals, QualType Canonical) bool isVariadic, unsigned typeQuals, bool hasExs,
bool hasAnyExs, const QualType *ExArray,
unsigned numExs, QualType Canonical)
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
(Result->isDependentType() || (Result->isDependentType() ||
hasAnyDependentType(ArgArray, numArgs))), hasAnyDependentType(ArgArray, numArgs))),
NumArgs(numArgs) { NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
AnyExceptionSpec(hasAnyExs) {
// Fill in the trailing argument array. // Fill in the trailing argument array.
QualType *ArgInfo = reinterpret_cast<QualType *>(this+1);; QualType *ArgInfo = reinterpret_cast<QualType*>(this+1);
for (unsigned i = 0; i != numArgs; ++i) for (unsigned i = 0; i != numArgs; ++i)
ArgInfo[i] = ArgArray[i]; ArgInfo[i] = ArgArray[i];
// Fill in the exception array.
QualType *Ex = ArgInfo + numArgs;
for (unsigned i = 0; i != numExs; ++i)
Ex[i] = ExArray[i];
} }
/// NumArgs - The number of arguments this function has, not counting '...'. /// NumArgs - The number of arguments this function has, not counting '...'.
unsigned NumArgs; unsigned NumArgs : 20;
/// NumExceptions - The number of types in the exception spec, if any.
unsigned NumExceptions : 10;
/// HasExceptionSpec - Whether this function has an exception spec at all.
bool HasExceptionSpec : 1;
/// AnyExceptionSpec - Whether this function has a throw(...) spec.
bool AnyExceptionSpec : 1;
/// ArgInfo - There is an variable size array after the class in memory that /// ArgInfo - There is an variable size array after the class in memory that
/// holds the argument types. /// holds the argument types.
/// Exceptions - There is another variable size array after ArgInfo that
/// holds the exception types.
friend class ASTContext; // ASTContext creates these. friend class ASTContext; // ASTContext creates these.
public: public:
@ -1189,7 +1210,15 @@ public:
assert(i < NumArgs && "Invalid argument number!"); assert(i < NumArgs && "Invalid argument number!");
return arg_type_begin()[i]; return arg_type_begin()[i];
} }
bool hasExceptionSpec() const { return HasExceptionSpec; }
bool hasAnyExceptionSpec() const { return AnyExceptionSpec; }
unsigned getNumExceptions() const { return NumExceptions; }
QualType getExceptionType(unsigned i) const {
assert(i < NumExceptions && "Invalid exception number!");
return exception_begin()[i];
}
bool isVariadic() const { return getSubClassData(); } bool isVariadic() const { return getSubClassData(); }
unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
@ -1198,18 +1227,29 @@ public:
return reinterpret_cast<const QualType *>(this+1); return reinterpret_cast<const QualType *>(this+1);
} }
arg_type_iterator arg_type_end() const { return arg_type_begin()+NumArgs; } arg_type_iterator arg_type_end() const { return arg_type_begin()+NumArgs; }
typedef const QualType *exception_iterator;
exception_iterator exception_begin() const {
// exceptions begin where arguments end
return arg_type_end();
}
exception_iterator exception_end() const {
return exception_begin() + NumExceptions;
}
virtual void getAsStringInternal(std::string &InnerString) const; virtual void getAsStringInternal(std::string &InnerString) const;
static bool classof(const Type *T) { static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto; return T->getTypeClass() == FunctionProto;
} }
static bool classof(const FunctionProtoType *) { return true; } static bool classof(const FunctionProtoType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID); void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, unsigned NumArgs, arg_type_iterator ArgTys, unsigned NumArgs,
bool isVariadic, unsigned TypeQuals); bool isVariadic, unsigned TypeQuals,
bool hasExceptionSpec, bool anyExceptionSpec,
unsigned NumExceptions, exception_iterator Exs);
}; };

Просмотреть файл

@ -1261,49 +1261,58 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) {
/// list. isVariadic indicates whether the argument list includes '...'. /// list. isVariadic indicates whether the argument list includes '...'.
QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
unsigned NumArgs, bool isVariadic, unsigned NumArgs, bool isVariadic,
unsigned TypeQuals) { unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec, unsigned NumExs,
const QualType *ExArray) {
// Unique functions, to guarantee there is only one function of a particular // Unique functions, to guarantee there is only one function of a particular
// structure. // structure.
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals); TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
NumExs, ExArray);
void *InsertPos = 0; void *InsertPos = 0;
if (FunctionProtoType *FTP = if (FunctionProtoType *FTP =
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FTP, 0); return QualType(FTP, 0);
// Determine whether the type being created is already canonical or not. // Determine whether the type being created is already canonical or not.
bool isCanonical = ResultTy->isCanonical(); bool isCanonical = ResultTy->isCanonical();
if (hasExceptionSpec)
isCanonical = false;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i) for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i]->isCanonical()) if (!ArgArray[i]->isCanonical())
isCanonical = false; isCanonical = false;
// If this type isn't canonical, get the canonical version of it. // If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical; QualType Canonical;
if (!isCanonical) { if (!isCanonical) {
llvm::SmallVector<QualType, 16> CanonicalArgs; llvm::SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs); CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i) for (unsigned i = 0; i != NumArgs; ++i)
CanonicalArgs.push_back(getCanonicalType(ArgArray[i])); CanonicalArgs.push_back(getCanonicalType(ArgArray[i]));
Canonical = getFunctionType(getCanonicalType(ResultTy), Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs, CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals); isVariadic, TypeQuals);
// Get the new insert position for the node we care about. // Get the new insert position for the node we care about.
FunctionProtoType *NewIP = FunctionProtoType *NewIP =
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos); FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
} }
// FunctionProtoType objects are allocated with extra bytes after them // FunctionProtoType objects are allocated with extra bytes after them
// for a variable size array (for parameter types) at the end of them. // for two variable size arrays (for parameter and exception types) at the
// end of them.
FunctionProtoType *FTP = FunctionProtoType *FTP =
(FunctionProtoType*)Allocate(sizeof(FunctionProtoType) + (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) +
NumArgs*sizeof(QualType), 8); NumArgs*sizeof(QualType) +
NumExs*sizeof(QualType), 8);
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, Canonical); TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
ExArray, NumExs, Canonical);
Types.push_back(FTP); Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos); FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0); return QualType(FTP, 0);
@ -2912,6 +2921,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
allRTypes = false; allRTypes = false;
if (lproto && rproto) { // two C99 style function prototypes if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
"C++ shouldn't be here");
unsigned lproto_nargs = lproto->getNumArgs(); unsigned lproto_nargs = lproto->getNumArgs();
unsigned rproto_nargs = rproto->getNumArgs(); unsigned rproto_nargs = rproto->getNumArgs();
@ -2950,6 +2961,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionProtoType *proto = lproto ? lproto : rproto; const FunctionProtoType *proto = lproto ? lproto : rproto;
if (proto) { if (proto) {
assert(!proto->hasExceptionSpec() && "C++ shouldn't be here");
if (proto->isVariadic()) return QualType(); if (proto->isVariadic()) return QualType();
// Check that the types are compatible with the types that // Check that the types are compatible with the types that
// would result from default argument promotions (C99 6.7.5.3p15). // would result from default argument promotions (C99 6.7.5.3p15).

Просмотреть файл

@ -927,17 +927,26 @@ const char *BuiltinType::getName() const {
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, arg_type_iterator ArgTys,
unsigned NumArgs, bool isVariadic, unsigned NumArgs, bool isVariadic,
unsigned TypeQuals) { unsigned TypeQuals, bool hasExceptionSpec,
bool anyExceptionSpec, unsigned NumExceptions,
exception_iterator Exs) {
ID.AddPointer(Result.getAsOpaquePtr()); ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i) for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr()); ID.AddPointer(ArgTys[i].getAsOpaquePtr());
ID.AddInteger(isVariadic); ID.AddInteger(isVariadic);
ID.AddInteger(TypeQuals); ID.AddInteger(TypeQuals);
ID.AddInteger(hasExceptionSpec);
if (hasExceptionSpec) {
ID.AddInteger(anyExceptionSpec);
for(unsigned i = 0; i != NumExceptions; ++i)
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
} }
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
getTypeQuals()); getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
getNumExceptions(), exception_begin());
} }
void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,

Просмотреть файл

@ -1670,8 +1670,16 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
ParamTypes.push_back(GetType(Record[Idx++])); ParamTypes.push_back(GetType(Record[Idx++]));
bool isVariadic = Record[Idx++]; bool isVariadic = Record[Idx++];
unsigned Quals = Record[Idx++]; unsigned Quals = Record[Idx++];
bool hasExceptionSpec = Record[Idx++];
bool hasAnyExceptionSpec = Record[Idx++];
unsigned NumExceptions = Record[Idx++];
llvm::SmallVector<QualType, 2> Exceptions;
for (unsigned I = 0; I != NumExceptions; ++I)
Exceptions.push_back(GetType(Record[Idx++]));
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
isVariadic, Quals); isVariadic, Quals, hasExceptionSpec,
hasAnyExceptionSpec, NumExceptions,
Exceptions.data());
} }
case pch::TYPE_TYPEDEF: case pch::TYPE_TYPEDEF:

Просмотреть файл

@ -162,6 +162,11 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
Writer.AddTypeRef(T->getArgType(I), Record); Writer.AddTypeRef(T->getArgType(I), Record);
Record.push_back(T->isVariadic()); Record.push_back(T->isVariadic());
Record.push_back(T->getTypeQuals()); Record.push_back(T->getTypeQuals());
Record.push_back(T->hasExceptionSpec());
Record.push_back(T->hasAnyExceptionSpec());
Record.push_back(T->getNumExceptions());
for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
Writer.AddTypeRef(T->getExceptionType(I), Record);
Code = pch::TYPE_FUNCTION_PROTO; Code = pch::TYPE_FUNCTION_PROTO;
} }

Просмотреть файл

@ -729,6 +729,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
(OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) { (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
// The old declaration provided a function prototype, but the // The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype. // new declaration does not. Merge in the prototype.
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(), llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
OldProto->arg_type_end()); OldProto->arg_type_end());
NewQType = Context.getFunctionType(NewFuncType->getResultType(), NewQType = Context.getFunctionType(NewFuncType->getResultType(),

Просмотреть файл

@ -999,6 +999,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ClassType = Context.getTypeDeclType(ClassDecl);
ClassType = Context.getCanonicalType(ClassType); ClassType = Context.getCanonicalType(ClassType);
// FIXME: Implicit declarations have exception specifications, which are
// the union of the specifications of the implicitly called functions.
if (!ClassDecl->hasUserDeclaredConstructor()) { if (!ClassDecl->hasUserDeclaredConstructor()) {
// C++ [class.ctor]p5: // C++ [class.ctor]p5:
// A default constructor for a class X is a constructor of class X // A default constructor for a class X is a constructor of class X

Просмотреть файл

@ -716,12 +716,20 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
T = Context.IntTy; T = Context.IntTy;
D.setInvalidType(true); D.setInvalidType(true);
} }
if (FTI.NumArgs == 0) { if (FTI.NumArgs == 0) {
if (getLangOptions().CPlusPlus) { if (getLangOptions().CPlusPlus) {
// C++ 8.3.5p2: If the parameter-declaration-clause is empty, the // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the
// function takes no arguments. // function takes no arguments.
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals); 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]));
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
FTI.NumExceptions, 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"
@ -795,8 +803,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
ArgTys.push_back(ArgTy); ArgTys.push_back(ArgTy);
} }
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]));
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.hasAnyExceptionSpec,
FTI.NumExceptions, Exceptions.data());
} }
break; break;
} }