Ping...
Patch is reattached, rebased against current TOT.
Chip
Charles Davis wrote:
> Douglas Gregor wrote:
>> On Dec 21, 2009, at 7:01 PM, Charles Davis wrote:
>>
>>> Douglas Gregor wrote:
>>>> On Dec 16, 2009, at 1:12 PM, Charles Davis wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> This patch encodes calling conventions into FunctionType objects. Right
>>>>> now, only cdecl, stdcall, and fastcall are supported. No real users yet,
>>>>> but I went through and fixed all the users of
>>>>> ASTContext::getFunctionType() and friends to respect the calling
>>>>> convention.
>>>>>
>>>>> Next up: applying calling convention attributes to the function types.
>>>> Comments below.
>>> How's the attached patch? (Responses to particular comments below.)
>> Very nice! A few little issues below, then I'd like to put this into Clang.
> As they say, third time's the charm. Here it is.
>>>>> Index: include/clang/AST/ASTContext.h
>>>>> ===================================================================
>>>>> --- include/clang/AST/ASTContext.h (revision 91549)
>>>>> +++ include/clang/AST/ASTContext.h (working copy)
>>>>> @@ -399,6 +399,11 @@
>>>>> /// 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, unsigned CallConv);
>>>>> +
>>>> The calling convention needs to be an enumeration (defined in Type.h)
>>>> rather than just an "unsigned". We're only likely to support a few
>>>> calling conventions, and adding new ones will be a non-trivial undertaking.
>>> Done.
>>>>> /// getComplexType - Return the uniqued reference to the type for a
>>>>> complex
>>>>> /// number with the specified element type.
>>>>> QualType getComplexType(QualType T);
>>>>> @@ -515,7 +520,8 @@
>>>>>
>>>>> /// 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,
>>>>> + unsigned CallConv = 0);
>>>>>
>>>>> /// getFunctionType - Return a normal function type with a typed
>>>>> argument
>>>>> /// list. isVariadic indicates whether the argument list includes
>>>>> '...'.
>>>>> @@ -524,7 +530,7 @@
>>>>> unsigned TypeQuals, bool hasExceptionSpec =
>>>>> false,
>>>>> bool hasAnyExceptionSpec = false,
>>>>> unsigned NumExs = 0, const QualType
>>>>> *ExArray = 0,
>>>>> - bool NoReturn = false);
>>>>> + bool NoReturn = false, unsigned CallConv =
>>>>> 0);
>>>>>
>>>>> /// getTypeDeclType - Return the unique reference to the type for
>>>>> /// the specified type declaration.
>>>>> Index: include/clang/AST/Type.h
>>>>> ===================================================================
>>>>> --- include/clang/AST/Type.h (revision 91549)
>>>>> +++ include/clang/AST/Type.h (working copy)
>>>>> @@ -1708,21 +1708,26 @@
>>>>> /// NoReturn - Indicates if the function type is attribute noreturn.
>>>>> unsigned NoReturn : 1;
>>>>>
>>>>> + /// CallConv - The calling convention used by the function. Is 0
>>>>> + /// for default, 1 for C, 2 for stdcall, and 3 for fastcall.
>>>>> + 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, unsigned callConv = 0)
>>>>> : 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; }
>>>>> + unsigned getCallConv() const { return CallConv; }
>>>> Any change to one of the ASTs requires a (de-)serialization code for
>>>> Clang's precompiled headers. PCHWriter.cpp and PCHReader.cpp will need
>>>> to be updated to include the calling convention.
>>> Are you sure? I looked at PCHWriter.cpp, and I didn't see any special
>>> handling for the noreturn attribute, even when it's stored as part of
>>> the type. It looks like PCHWriter just stores the noreturn attribute
>>> itself into the PCH.
>> Oops, that was a bug; fixed in r91911. The calling convention and noreturn
>> both need to be serialized to PCH.
>>
> Alright, I've (de)serialized the calling convention to/from the
> FunctionType in the PCH handlers.
>>>>> +QualType ASTContext::getCallConvType(QualType T, unsigned CallConv) {
>>>>> + QualType ResultType;
>>>>> + if (const PointerType *Pointer = T->getAs<PointerType>()) {
>>>>> + QualType Pointee = Pointer->getPointeeType();
>>>>> + ResultType = getCallConvType(Pointee, CallConv);
>>>>> + if (ResultType == Pointee)
>>>>> + return T;
>>>>> +
>>>>> + ResultType = getPointerType(ResultType);
>>>>> + } else if (const FunctionType *F = T->getAs<FunctionType>()) {
>>>>> + if (F->getCallConv() == CallConv)
>>>>> + return T;
>>>>> +
>>>>> + if (const FunctionNoProtoType *FNPT =
>>>>> dyn_cast<FunctionNoProtoType>(F)) {
>>>>> + ResultType = getFunctionNoProtoType(FNPT->getResultType(),
>>>>> + FNPT->getNoReturn(),
>>>>> 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(),
>>>>> + FPT->getNoReturn(), CallConv);
>>>>> + }
>>>>> + } else
>>>>> + return T;
>>>>> +
>>>>> + return getQualifiedType(ResultType, T.getLocalQualifiers());
>>>>> +}
>>>> It's really unfortunate that this code is nearly a copy of
>>>> getNoReturnType. Is there a way to consolidate the two?
>>> Took me a while, but I found one. The problem was that, when I called
>>> the common function from getNoReturnType() (or its brother
>>> getCallConvType()), I needed a default value for the attribute I wasn't
>>> setting. The obvious place to get it from would be from the type itself,
>>> but then there's the case where the get*Type() methods get called on
>>> something that isn't a function type. So I added a method to QualType
>>> that does the check and grabs the calling convention from the FunctionType.
>> Okay, sounds good.
>>
>>> Index: include/clang/AST/ASTContext.h
>>> ===================================================================
>>> --- include/clang/AST/ASTContext.h (revision 91861)
>>> +++ include/clang/AST/ASTContext.h (working copy)
>>> @@ -400,6 +400,11 @@
>>> /// 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);
>>> @@ -516,7 +521,8 @@
>>>
>>> /// 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 '...'.
>>> @@ -525,7 +531,8 @@
>>> 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.
>>> Index: include/clang/AST/Type.h
>>> ===================================================================
>>> --- include/clang/AST/Type.h (revision 91861)
>>> +++ include/clang/AST/Type.h (working copy)
>>> @@ -385,7 +385,15 @@
>>> }
>>> };
>>>
>>> +/// 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
>>> /// greatly reduces the number of nodes we need to allocate for types (for
>>> @@ -664,6 +672,10 @@
>>> /// 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
>>> @@ -1708,21 +1720,25 @@
>>> /// NoReturn - Indicates if the function type is attribute noreturn.
>>> unsigned NoReturn : 1;
>>>
>>> + /// CallConv - The calling convention used by the function.
>>> + CallingConv CallConv : 2;
>>> +
>> MSVC has an annoying bug w.r.t. bit-fields of enum type, so this bit-field
>> needs to be declared as
>>
>> unsigned CallConv : 2;
> Microsoft sucks. That's why I use a Mac :). But, since many people still
> use Windows, I concede to your infinite wisdom.
>>> +/// 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 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;
>>> +}
>> It seems like this should cope with ReferenceType and MemberPointerType
>> nodes as well since, IIRC, you can have references and member pointers to
>> functions with specific calling conventions. That's not specifically your
>> problem, though, so it won't hold up your patch.
> Well, I did it anyway. I would have taken the liberty of fixing
> getNoReturnAttr() too, but I think my patch is big enough as it is.
>>> Index: lib/AST/ASTContext.cpp
>>> ===================================================================
>>> --- lib/AST/ASTContext.cpp (revision 91861)
>>> +++ lib/AST/ASTContext.cpp (working copy)
>>> @@ -1200,45 +1200,60 @@
>>> 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());
>>> }
>>
>> Great, thanks!
>>
>> @@ -4213,6 +4231,11 @@
>> allLTypes = false;
>> if (NoReturn != rbase->getNoReturnAttr())
>> allRTypes = false;
>> + CallingConv lcc = lbase->getCallConv();
>> + CallingConv rcc = rbase->getCallConv();
>> + // Compatible functions must have the same calling convention
>> + if((lcc == 0 || rcc != 0) && lcc != rcc)
>> + return QualType();
>>
>> I find this logic a bit hard to follow... could you abstract out an "is same
>> calling convention" predicate, so that we can turn this into just
>>
>> if (!isSameCallingConvention(lcc, rcc))
>> return QualType();
> I think I worded that comment wrong. What I'm really testing is if the
> calling conventions are "compatible". In MSVC, for example, it's
> possible to declare a function with a calling convention:
>
> int __stdcall f(int, int);
>
> and then define it without specifying the calling convention:
>
> int f(int a, int b) {return a+b;}
>
> I've outlined what this means in the isCompatibleCallingConvention()
> function.
>> It'll be very helpful for all of the other places where we'll need to check
>> for equivalence of calling conventions.
> Agreed.
>
> Chip
>
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h (revision 92538)
+++ include/clang/AST/ASTContext.h (working copy)
@@ -397,6 +397,11 @@
/// 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 @@
/// 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 @@
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.
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h (revision 92538)
+++ include/clang/AST/Type.h (working copy)
@@ -385,7 +385,15 @@
}
};
+/// 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
/// greatly reduces the number of nodes we need to allocate for types (for
@@ -669,6 +677,10 @@
/// 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 @@
/// 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 @@
/// 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 @@
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 @@
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
Index: lib/Frontend/PCHWriter.cpp
===================================================================
--- lib/Frontend/PCHWriter.cpp (revision 92538)
+++ lib/Frontend/PCHWriter.cpp (working copy)
@@ -139,6 +139,7 @@
void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
Writer.AddTypeRef(T->getResultType(), Record);
Record.push_back(T->getNoReturnAttr());
+ Record.push_back(T->getCallConv());
}
void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
Index: lib/Frontend/PCHReader.cpp
===================================================================
--- lib/Frontend/PCHReader.cpp (revision 92538)
+++ lib/Frontend/PCHReader.cpp (working copy)
@@ -1909,18 +1909,20 @@
}
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 @@
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
isVariadic, Quals, hasExceptionSpec,
hasAnyExceptionSpec, NumExceptions,
- Exceptions.data(), NoReturn);
+ Exceptions.data(), NoReturn, CallConv);
}
case pch::TYPE_UNRESOLVED_USING:
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp (revision 92538)
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp (working copy)
@@ -1542,7 +1542,8 @@
Proto->hasAnyExceptionSpec(),
Exceptions.size(),
Exceptions.data(),
- Proto->getNoReturnAttr()));
+ Proto->getNoReturnAttr(),
+ Proto->getCallConv()));
}
return false;
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp (revision 92538)
+++ lib/AST/ASTContext.cpp (working copy)
@@ -1200,45 +1200,60 @@
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
/// number with the specified element type.
QualType ASTContext::getComplexType(QualType T) {
@@ -1681,7 +1696,8 @@
/// 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;
@@ -1694,7 +1710,8 @@
QualType Canonical;
if (!ResultTy.isCanonical()) {
- Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn);
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
+ CallConv);
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -1715,7 +1732,8 @@
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;
@@ -1746,7 +1764,7 @@
Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false,
- false, 0, 0, NoReturn);
+ false, 0, 0, NoReturn, CallConv);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1763,7 +1781,7 @@
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);
@@ -4213,6 +4231,17 @@
return !mergeTypes(LHS, RHS).isNull();
}
+static bool isCompatibleCallingConvention(CallingConv lcc, CallingConv rcc) {
+ // Here are the rules (as I see them) for compatibility of calling
+ // conventions:
+ // - If they're the same, they're compatible.
+ // - If the first one is not the default and the second one is, then
+ // they're compatible (and the second declaration assumes the calling
+ // convention of the first).
+ // - Otherwise, they're not compatible.
+ return (lcc == rcc || (lcc != CC_Default && rcc == CC_Default));
+}
+
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>();
@@ -4234,6 +4263,11 @@
allLTypes = false;
if (NoReturn != rbase->getNoReturnAttr())
allRTypes = false;
+ CallingConv lcc = lbase->getCallConv();
+ CallingConv rcc = rbase->getCallConv();
+ // Compatible functions must have compatible calling conventions
+ if (!isCompatibleCallingConvention(lcc, rcc))
+ return QualType();
if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
@@ -4269,7 +4303,7 @@
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic(), lproto->getTypeQuals(),
- NoReturn);
+ NoReturn, lcc);
}
if (lproto) allRTypes = false;
@@ -4296,12 +4330,12 @@
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) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits