From 7b9a2ee5a4393001bdec7dec841eb7c811da492c Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Thu, 30 Apr 2009 19:20:55 +0000 Subject: [PATCH] Make a home for exception specs in the AST. Now Sema can hook them up. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70506 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 6 ++-- include/clang/AST/Type.h | 60 +++++++++++++++++++++++++++------- lib/AST/ASTContext.cpp | 34 +++++++++++++------ lib/AST/Type.cpp | 13 ++++++-- lib/Frontend/PCHReader.cpp | 10 +++++- lib/Frontend/PCHWriter.cpp | 5 +++ lib/Sema/SemaDecl.cpp | 1 + lib/Sema/SemaDeclCXX.cpp | 3 ++ 8 files changed, 106 insertions(+), 26 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 8cb1056110..fef2ed7231 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -292,12 +292,14 @@ public: /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType getFunctionNoProtoType(QualType ResultTy); - + /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. QualType getFunctionType(QualType ResultTy, const QualType *ArgArray, 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 /// the specified type declaration. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 3e8d024d72..fbe4a7f3d5 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1152,23 +1152,42 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { } 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, (Result->isDependentType() || hasAnyDependentType(ArgArray, numArgs))), - NumArgs(numArgs) { + NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs), + AnyExceptionSpec(hasAnyExs) { // Fill in the trailing argument array. - QualType *ArgInfo = reinterpret_cast(this+1);; + QualType *ArgInfo = reinterpret_cast(this+1); for (unsigned i = 0; i != numArgs; ++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 '...'. - 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 /// holds the argument types. - + + /// Exceptions - There is another variable size array after ArgInfo that + /// holds the exception types. + friend class ASTContext; // ASTContext creates these. public: @@ -1177,7 +1196,15 @@ public: assert(i < NumArgs && "Invalid argument number!"); 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(); } unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } @@ -1186,18 +1213,29 @@ public: return reinterpret_cast(this+1); } 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; static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; } static bool classof(const FunctionProtoType *) { return true; } - + void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, arg_type_iterator ArgTys, unsigned NumArgs, - bool isVariadic, unsigned TypeQuals); + bool isVariadic, unsigned TypeQuals, + bool hasExceptionSpec, bool anyExceptionSpec, + unsigned NumExceptions, exception_iterator Exs); }; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b88149ad41..0494de199f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1321,12 +1321,15 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) { /// list. isVariadic indicates whether the argument list includes '...'. QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, 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 // structure. llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, - TypeQuals); + TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, + NumExs, ExArray); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1346,24 +1349,32 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) CanonicalArgs.push_back(getCanonicalType(ArgArray[i])); - + llvm::SmallVector CanonicalExs; + CanonicalExs.reserve(NumExs); + for (unsigned i = 0; i != NumExs; ++i) + CanonicalExs.push_back(getCanonicalType(ExArray[i])); + Canonical = getFunctionType(getCanonicalType(ResultTy), &CanonicalArgs[0], NumArgs, - isVariadic, TypeQuals); - + isVariadic, TypeQuals, hasExceptionSpec, + hasAnyExceptionSpec, NumExs, &CanonicalExs[0]); + // Get the new insert position for the node we care about. FunctionProtoType *NewIP = FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - + // 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*)Allocate(sizeof(FunctionProtoType) + - NumArgs*sizeof(QualType), 8); + (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) + + NumArgs*sizeof(QualType) + + NumExs*sizeof(QualType), 8); new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, - TypeQuals, Canonical); + TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, + ExArray, NumExs, Canonical); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -2930,6 +2941,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { allRTypes = false; if (lproto && rproto) { // two C99 style function prototypes + assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && + "C++ shouldn't be here"); unsigned lproto_nargs = lproto->getNumArgs(); unsigned rproto_nargs = rproto->getNumArgs(); @@ -2968,6 +2981,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionProtoType *proto = lproto ? lproto : rproto; if (proto) { + assert(!proto->hasExceptionSpec() && "C++ shouldn't be here"); if (proto->isVariadic()) return QualType(); // Check that the types are compatible with the types that // would result from default argument promotions (C99 6.7.5.3p15). diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d6cf4bd0c3..9308288ce3 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -920,17 +920,26 @@ const char *BuiltinType::getName() const { void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, arg_type_iterator ArgTys, unsigned NumArgs, bool isVariadic, - unsigned TypeQuals) { + unsigned TypeQuals, bool hasExceptionSpec, + bool anyExceptionSpec, unsigned NumExceptions, + exception_iterator Exs) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); ID.AddInteger(isVariadic); 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) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), - getTypeQuals()); + getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), + getNumExceptions(), exception_begin()); } void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 9323620938..949d02a985 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1584,8 +1584,16 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { ParamTypes.push_back(GetType(Record[Idx++])); bool isVariadic = Record[Idx++]; unsigned Quals = Record[Idx++]; + bool hasExceptionSpec = Record[Idx++]; + bool hasAnyExceptionSpec = Record[Idx++]; + unsigned NumExceptions = Record[Idx++]; + llvm::SmallVector Exceptions; + for (unsigned I = 0; I != NumExceptions; ++I) + Exceptions.push_back(GetType(Record[Idx++])); return Context->getFunctionType(ResultType, &ParamTypes[0], NumParams, - isVariadic, Quals); + isVariadic, Quals, hasExceptionSpec, + hasAnyExceptionSpec, NumExceptions, + &Exceptions[0]); } case pch::TYPE_TYPEDEF: diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index b28d0c8cf9..2db93c3bb9 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -161,6 +161,11 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Writer.AddTypeRef(T->getArgType(I), Record); Record.push_back(T->isVariadic()); 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; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9e2bd444f8..2381c62575 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -714,6 +714,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { (OldProto = dyn_cast(OldFuncType))) { // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. + assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); llvm::SmallVector ParamTypes(OldProto->arg_type_begin(), OldProto->arg_type_end()); NewQType = Context.getFunctionType(NewFuncType->getResultType(), diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 71d2f80cfc..e9b7fb04ce 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -995,6 +995,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { QualType ClassType = Context.getTypeDeclType(ClassDecl); 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()) { // C++ [class.ctor]p5: // A default constructor for a class X is a constructor of class X -- 2.40.0