Encoding calling conventions in the type system, from Charles Davis!

llvm-svn: 93726
This commit is contained in:
Douglas Gregor 2010-01-18 17:14:39 +00:00
parent 07894e8a0e
commit 8c94086c90
6 changed files with 127 additions and 42 deletions

View File

@ -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.

View File

@ -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

View File

@ -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) {

View File

@ -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:

View File

@ -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) {

View File

@ -1548,7 +1548,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Proto->hasAnyExceptionSpec(),
Exceptions.size(),
Exceptions.data(),
Proto->getNoReturnAttr()));
Proto->getNoReturnAttr(),
Proto->getCallConv()));
}
return false;