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 91918)
+++ 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 91918)
+++ 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.
+  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 ||
@@ -1735,9 +1751,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.
@@ -1779,10 +1795,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.
@@ -2801,6 +2819,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 91918)
+++ lib/Frontend/PCHWriter.cpp  (working copy)
@@ -145,6 +145,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 91918)
+++ lib/Frontend/PCHReader.cpp  (working copy)
@@ -1854,18 +1854,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)
@@ -1881,7 +1883,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 91918)
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp    (working copy)
@@ -1529,7 +1529,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 91918)
+++ lib/AST/ASTContext.cpp      (working copy)
@@ -1210,45 +1210,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) {
@@ -1700,7 +1715,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;
@@ -1713,7 +1729,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 =
@@ -1734,7 +1751,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;
@@ -1765,7 +1783,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 =
@@ -1782,7 +1800,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);
@@ -4202,6 +4220,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>();
@@ -4223,6 +4252,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() &&
@@ -4258,7 +4292,7 @@
     if (allRTypes) return rhs;
     return getFunctionType(retType, types.begin(), types.size(),
                            lproto->isVariadic(), lproto->getTypeQuals(),
-                           NoReturn);
+                           NoReturn, lcc);
   }
 
   if (lproto) allRTypes = false;
@@ -4285,12 +4319,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

Reply via email to