forked from OSchip/llvm-project
Encoding calling conventions in the type system, from Charles Davis!
llvm-svn: 93726
This commit is contained in:
parent
07894e8a0e
commit
8c94086c90
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1548,7 +1548,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
|
|||
Proto->hasAnyExceptionSpec(),
|
||||
Exceptions.size(),
|
||||
Exceptions.data(),
|
||||
Proto->getNoReturnAttr()));
|
||||
Proto->getNoReturnAttr(),
|
||||
Proto->getCallConv()));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue