diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 6 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 64 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 34 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 13 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 10 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 23 |
9 files changed, 128 insertions, 31 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 335fc40aea..0badd81be0 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -287,12 +287,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 78cd8de133..5361ffb730 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1151,7 +1151,9 @@ public: /// FunctionProtoType - Represents a prototype with argument type info, e.g. /// '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 { /// hasAnyDependentType - Determine whether there are any dependent /// 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, - 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<QualType *>(this+1);; + QualType *ArgInfo = reinterpret_cast<QualType*>(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: @@ -1189,7 +1210,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(); } @@ -1198,18 +1227,29 @@ public: return reinterpret_cast<const QualType *>(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 0db5f9b2bf..b230edb93d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1261,49 +1261,58 @@ 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 = FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) 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(); + if (hasExceptionSpec) + isCanonical = false; for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i]->isCanonical()) isCanonical = false; // If this type isn't canonical, get the canonical version of it. + // The exception spec is not part of the canonical type. QualType Canonical; if (!isCanonical) { llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) CanonicalArgs.push_back(getCanonicalType(ArgArray[i])); - + Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals); - + // 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); @@ -2912,6 +2921,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(); @@ -2950,6 +2961,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 6093352021..c04e8275ef 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -927,17 +927,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 46f4fb7254..63e4337c88 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1670,8 +1670,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<QualType, 2> Exceptions; + for (unsigned I = 0; I != NumExceptions; ++I) + Exceptions.push_back(GetType(Record[Idx++])); return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, - isVariadic, Quals); + isVariadic, Quals, hasExceptionSpec, + hasAnyExceptionSpec, NumExceptions, + Exceptions.data()); } case pch::TYPE_TYPEDEF: diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 2d3ca17036..9f9b3b4e09 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -162,6 +162,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 d592cf6178..7b36b13416 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -729,6 +729,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { (OldProto = dyn_cast<FunctionProtoType>(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<QualType, 16> 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 ebe34064d6..6edb29044c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -999,6 +999,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 diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 19ff9bbd4c..298a6cddda 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -716,12 +716,20 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { T = Context.IntTy; D.setInvalidType(true); } - + if (FTI.NumArgs == 0) { if (getLangOptions().CPlusPlus) { // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the // 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) { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" @@ -795,8 +803,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { 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(), - FTI.isVariadic, FTI.TypeQuals); + FTI.isVariadic, FTI.TypeQuals, + FTI.hasExceptionSpec, + FTI.hasAnyExceptionSpec, + FTI.NumExceptions, Exceptions.data()); } break; } |