diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-01-18 17:14:39 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-01-18 17:14:39 +0000 |
commit | ab8bbf4ebd3e3e6eab913cb044772a62b7581941 (patch) | |
tree | 6a9c15fe9aecee4326568409b43782b770554169 | |
parent | 35aa62aacf2b644f2ff2f0bdfd89136323698a39 (diff) |
Encoding calling conventions in the type system, from Charles Davis!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93726 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 11 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 50 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 93 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 10 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 |
6 files changed, 127 insertions, 42 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 5db8e20e7e..2d151ff83a 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -397,6 +397,11 @@ public: /// BlockPointer. QualType getNoReturnType(QualType T, bool AddNoReturn = true); + /// getCallConvType - Adds the specified calling convention attribute to + /// the given type, which must be a FunctionType or a pointer to an + /// allowable type. + QualType getCallConvType(QualType T, CallingConv CallConv); + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); @@ -513,7 +518,8 @@ public: /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// - QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false); + QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false, + CallingConv CallConv = CC_Default); /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. @@ -522,7 +528,8 @@ public: unsigned TypeQuals, bool hasExceptionSpec = false, bool hasAnyExceptionSpec = false, unsigned NumExs = 0, const QualType *ExArray = 0, - bool NoReturn = false); + bool NoReturn = false, + CallingConv CallConv = CC_Default); /// 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 9b0cdc3a52..8e534d35cd 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -385,6 +385,14 @@ public: } }; +/// CallingConv - Specifies the calling convention that a function uses. +enum CallingConv { + CC_Default, + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall // __attribute__((fastcall)) +}; + /// QualType - For efficiency, we don't store CV-qualified types as nodes on /// their own: instead each reference to a type stores the qualifiers. This @@ -669,6 +677,10 @@ public: /// false otherwise. bool getNoReturnAttr() const; + /// getCallConv - Returns the calling convention of the type if the type + /// is a function type, CC_Default otherwise. + CallingConv getCallConv() const; + private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the @@ -1691,21 +1703,25 @@ class FunctionType : public Type { /// NoReturn - Indicates if the function type is attribute noreturn. unsigned NoReturn : 1; + /// CallConv - The calling convention used by the function. + unsigned CallConv : 2; + // The type returned by the function. QualType ResultType; protected: FunctionType(TypeClass tc, QualType res, bool SubclassInfo, unsigned typeQuals, QualType Canonical, bool Dependent, - bool noReturn = false) + bool noReturn = false, CallingConv callConv = CC_Default) : Type(tc, Canonical, Dependent), SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn), - ResultType(res) {} + CallConv(callConv), ResultType(res) {} bool getSubClassData() const { return SubClassData; } unsigned getTypeQuals() const { return TypeQuals; } public: QualType getResultType() const { return ResultType; } bool getNoReturnAttr() const { return NoReturn; } + CallingConv getCallConv() const { return (CallingConv)CallConv; } static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || @@ -1718,9 +1734,9 @@ public: /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionNoProtoType(QualType Result, QualType Canonical, - bool NoReturn = false) + bool NoReturn = false, CallingConv CallConv = CC_Default) : FunctionType(FunctionNoProto, Result, false, 0, Canonical, - /*Dependent=*/false, NoReturn) {} + /*Dependent=*/false, NoReturn, CallConv) {} friend class ASTContext; // ASTContext creates these. public: // No additional state past what FunctionType provides. @@ -1762,10 +1778,12 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs, bool isVariadic, unsigned typeQuals, bool hasExs, bool hasAnyExs, const QualType *ExArray, - unsigned numExs, QualType Canonical, bool NoReturn) + unsigned numExs, QualType Canonical, bool NoReturn, + CallingConv CallConv) : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, (Result->isDependentType() || - hasAnyDependentType(ArgArray, numArgs)), NoReturn), + hasAnyDependentType(ArgArray, numArgs)), NoReturn, + CallConv), NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs), AnyExceptionSpec(hasAnyExs) { // Fill in the trailing argument array. @@ -2797,6 +2815,26 @@ inline bool QualType::getNoReturnAttr() const { return false; } +/// getCallConv - Returns the calling convention of the type if the type +/// is a function type, CC_Default otherwise. +inline CallingConv QualType::getCallConv() const { + if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) + return PT->getPointeeType().getCallConv(); + else if (const ReferenceType *RT = getTypePtr()->getAs<ReferenceType>()) + return RT->getPointeeType().getCallConv(); + else if (const MemberPointerType *MPT = + getTypePtr()->getAs<MemberPointerType>()) + return MPT->getPointeeType().getCallConv(); + else if (const BlockPointerType *BPT = + getTypePtr()->getAs<BlockPointerType>()) { + if (const FunctionType *FT = BPT->getPointeeType()->getAs<FunctionType>()) + return FT->getCallConv(); + } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>()) + return FT->getCallConv(); + + return CC_Default; +} + /// isMoreQualifiedThan - Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 76ec852cb8..c6e3e09fa5 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1200,43 +1200,58 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { +static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, + bool AddNoReturn, + CallingConv CallConv) { QualType ResultType; if (const PointerType *Pointer = T->getAs<PointerType>()) { QualType Pointee = Pointer->getPointeeType(); - ResultType = getNoReturnType(Pointee, AddNoReturn); + ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, + CallConv); if (ResultType == Pointee) return T; - - ResultType = getPointerType(ResultType); + + ResultType = Context.getPointerType(ResultType); } else if (const BlockPointerType *BlockPointer = T->getAs<BlockPointerType>()) { QualType Pointee = BlockPointer->getPointeeType(); - ResultType = getNoReturnType(Pointee, AddNoReturn); + ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, + CallConv); if (ResultType == Pointee) return T; - - ResultType = getBlockPointerType(ResultType); - } else if (const FunctionType *F = T->getAs<FunctionType>()) { - if (F->getNoReturnAttr() == AddNoReturn) + + ResultType = Context.getBlockPointerType(ResultType); + } else if (const FunctionType *F = T->getAs<FunctionType>()) { + if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv) return T; - + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { - ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn); + ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(), + AddNoReturn, CallConv); } else { const FunctionProtoType *FPT = cast<FunctionProtoType>(F); ResultType - = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), - FPT->getNumArgs(), FPT->isVariadic(), - FPT->getTypeQuals(), - FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(), - FPT->getNumExceptions(), FPT->exception_begin(), - AddNoReturn); + = Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), + FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), + FPT->exception_begin(), + AddNoReturn, CallConv); } } else return T; - - return getQualifiedType(ResultType, T.getLocalQualifiers()); + + return Context.getQualifiedType(ResultType, T.getLocalQualifiers()); +} + +QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { + return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv()); +} + +QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) { + return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1679,9 +1694,16 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } +static CallingConv getCanonicalCallingConv(CallingConv CC) { + if (CC == CC_C) + return CC_Default; + return CC; +} + /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { +QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, + CallingConv CallConv) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1693,8 +1715,10 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { return QualType(FT, 0); QualType Canonical; - if (!ResultTy.isCanonical()) { - Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); + if (!ResultTy.isCanonical() || + getCanonicalCallingConv(CallConv) != CallConv) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, + getCanonicalCallingConv(CallConv)); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1715,7 +1739,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, - const QualType *ExArray, bool NoReturn) { + const QualType *ExArray, bool NoReturn, + CallingConv CallConv) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1737,7 +1762,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // 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) { + if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -1746,7 +1771,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, - false, 0, 0, NoReturn); + false, 0, 0, NoReturn, + getCanonicalCallingConv(CallConv)); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1763,7 +1789,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, NumExs*sizeof(QualType), TypeAlignment); new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - ExArray, NumExs, Canonical, NoReturn); + ExArray, NumExs, Canonical, NoReturn, CallConv); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -4211,6 +4237,10 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS).isNull(); } +static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) { + return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc)); +} + QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>(); @@ -4232,6 +4262,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { allLTypes = false; if (NoReturn != rbase->getNoReturnAttr()) allRTypes = false; + CallingConv lcc = lbase->getCallConv(); + CallingConv rcc = rbase->getCallConv(); + // Compatible functions must have compatible calling conventions + if (!isSameCallingConvention(lcc, rcc)) + return QualType(); if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -4267,7 +4302,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), lproto->isVariadic(), lproto->getTypeQuals(), - NoReturn); + NoReturn, lcc); } if (lproto) allRTypes = false; @@ -4294,12 +4329,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, proto->arg_type_begin(), proto->getNumArgs(), proto->isVariadic(), - proto->getTypeQuals(), NoReturn); + proto->getTypeQuals(), NoReturn, lcc); } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionNoProtoType(retType, NoReturn); + return getFunctionNoProtoType(retType, NoReturn, lcc); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 07d5a78bea..1f23bd2141 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1909,18 +1909,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 2) { + if (Record.size() != 3) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - return Context->getFunctionNoProtoType(ResultType, Record[1]); + return Context->getFunctionNoProtoType(ResultType, Record[1], + (CallingConv)Record[2]); } case pch::TYPE_FUNCTION_PROTO: { QualType ResultType = GetType(Record[0]); bool NoReturn = Record[1]; - unsigned Idx = 2; + CallingConv CallConv = (CallingConv)Record[2]; + unsigned Idx = 3; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -1936,7 +1938,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, isVariadic, Quals, hasExceptionSpec, hasAnyExceptionSpec, NumExceptions, - Exceptions.data(), NoReturn); + Exceptions.data(), NoReturn, CallConv); } case pch::TYPE_UNRESOLVED_USING: diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 3f6841b545..21e09744e3 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -139,6 +139,8 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); Record.push_back(T->getNoReturnAttr()); + // FIXME: need to stabilize encoding of calling convention... + Record.push_back(T->getCallConv()); } void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 98619f3a16..e3a180a578 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1548,7 +1548,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Proto->hasAnyExceptionSpec(), Exceptions.size(), Exceptions.data(), - Proto->getNoReturnAttr())); + Proto->getNoReturnAttr(), + Proto->getCallConv())); } return false; |