From: Sebastian Redl Date: Wed, 27 May 2009 22:11:52 +0000 (+0000) Subject: Reintroduce the home for exception specs, and make Sema fill it. However, keep the... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=465226e23a3008bd68973513dda1f9e3cd27dbdd;p=clang 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 --- 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(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: @@ -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(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 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 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(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 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 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 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; }