[cfe-commits] [PATCH] Encoding calling conventions in FunctionTypes

Douglas Gregor dgregor at apple.com
Fri Dec 18 11:50:57 PST 2009


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.

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

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

Also, when you get to applying calling convention attributes to  
function types, please make sure to update the type printer as well.

>   static bool classof(const Type *T) {
>     return T->getTypeClass() == FunctionNoProto ||
> @@ -1735,9 +1740,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, unsigned CallConv = 0)
>     : 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 +1784,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,
> +                    unsigned CallConv = 0)
>     : 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.
> Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
> ===================================================================
> --- lib/Sema/SemaTemplateInstantiateDecl.cpp	(revision 91549)
> +++ lib/Sema/SemaTemplateInstantiateDecl.cpp	(working copy)
> @@ -1523,7 +1523,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 91549)
> +++ lib/AST/ASTContext.cpp	(working copy)
> @@ -1222,7 +1222,8 @@
>       return T;
>
>     if (const FunctionNoProtoType *FNPT =  
> dyn_cast<FunctionNoProtoType>(F)) {
> -      ResultType = getFunctionNoProtoType(FNPT->getResultType(),  
> AddNoReturn);
> +      ResultType = getFunctionNoProtoType(FNPT->getResultType(),  
> AddNoReturn,
> +                                          FNPT->getCallConv());
>     } else {
>       const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
>       ResultType
> @@ -1231,7 +1232,7 @@
>                           FPT->getTypeQuals(),
>                           FPT->hasExceptionSpec(), FPT- 
> >hasAnyExceptionSpec(),
>                           FPT->getNumExceptions(), FPT- 
> >exception_begin(),
> -                          AddNoReturn);
> +                          AddNoReturn, FPT->getCallConv());
>     }
>   } else
>     return T;
> @@ -1239,6 +1240,38 @@
>   return getQualifiedType(ResultType, T.getLocalQualifiers());
> }
>
> +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?

> /// getComplexType - Return the uniqued reference to the type for a  
> complex
> /// number with the specified element type.
> QualType ASTContext::getComplexType(QualType T) {
> @@ -1690,7 +1723,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,
> +                                            unsigned CallConv) {
>   // Unique functions, to guarantee there is only one function of a  
> particular
>   // structure.
>   llvm::FoldingSetNodeID ID;
> @@ -1703,7 +1737,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 =
> @@ -1724,7 +1759,8 @@
>                                      unsigned NumArgs, bool  
> isVariadic,
>                                      unsigned TypeQuals, bool  
> hasExceptionSpec,
>                                      bool hasAnyExceptionSpec,  
> unsigned NumExs,
> -                                     const QualType *ExArray, bool  
> NoReturn) {
> +                                     const QualType *ExArray, bool  
> NoReturn,
> +                                     unsigned CallConv) {
>   // Unique functions, to guarantee there is only one function of a  
> particular
>   // structure.
>   llvm::FoldingSetNodeID ID;
> @@ -1755,7 +1791,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 =
> @@ -1772,7 +1808,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 +4249,11 @@
>     allLTypes = false;
>   if (NoReturn != rbase->getNoReturnAttr())
>     allRTypes = false;
> +  unsigned lcc = lbase->getCallConv();
> +  unsigned rcc = rbase->getCallConv();
> +  // Compatible functions must have the same calling convention
> +  if((lcc == 0 || rcc != 0) && lcc != rcc)
> +    return QualType();
>
>   if (lproto && rproto) { // two C99 style function prototypes
>     assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec 
> () &&
> @@ -4248,7 +4289,7 @@
>     if (allRTypes) return rhs;
>     return getFunctionType(retType, types.begin(), types.size(),
>                            lproto->isVariadic(), lproto->getTypeQuals 
> (),
> -                           NoReturn);
> +                           NoReturn, lcc);
>   }
>
>   if (lproto) allRTypes = false;
> @@ -4275,12 +4316,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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list