]> granicus.if.org Git - clang/commitdiff
Allow calling convention attributes to apply to types. Patch by Chip Davis!
authorJohn McCall <rjmccall@apple.com>
Thu, 4 Feb 2010 05:44:44 +0000 (05:44 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 4 Feb 2010 05:44:44 +0000 (05:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95291 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaType.cpp
test/Sema/callingconv.c

index f53fd921067e7997f053b7d9ea0465fec37c4db3..fa5d3e105f85fa0cce45d326491891f45db235d5 100644 (file)
@@ -1766,10 +1766,11 @@ public:
   QualType desugar() const { return QualType(this, 0); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getResultType(), getNoReturnAttr());
+    Profile(ID, getResultType(), getNoReturnAttr(), getCallConv());
   }
   static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
-                      bool NoReturn) {
+                      bool NoReturn, CallingConv CallConv) {
+    ID.AddInteger(CallConv);
     ID.AddInteger(NoReturn);
     ID.AddPointer(ResultType.getAsOpaquePtr());
   }
@@ -1892,7 +1893,7 @@ public:
                       bool isVariadic, unsigned TypeQuals,
                       bool hasExceptionSpec, bool anyExceptionSpec,
                       unsigned NumExceptions, exception_iterator Exs,
-                      bool NoReturn);
+                      bool NoReturn, CallingConv CallConv);
 };
 
 
index d6c9041e3e97834eedc621e54b5e9119627655c7..52c5cbccdef4e6bfc70281d410fe380b54bfa58c 100644 (file)
@@ -1716,7 +1716,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
   // Unique functions, to guarantee there is only one function of a particular
   // structure.
   llvm::FoldingSetNodeID ID;
-  FunctionNoProtoType::Profile(ID, ResultTy, NoReturn);
+  FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv);
 
   void *InsertPos = 0;
   if (FunctionNoProtoType *FT =
@@ -1736,7 +1736,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
   }
 
   FunctionNoProtoType *New = new (*this, TypeAlignment)
-    FunctionNoProtoType(ResultTy, Canonical, NoReturn);
+    FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv);
   Types.push_back(New);
   FunctionNoProtoTypes.InsertNode(New, InsertPos);
   return QualType(New, 0);
@@ -1755,7 +1755,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
   llvm::FoldingSetNodeID ID;
   FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
                              TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
-                             NumExs, ExArray, NoReturn);
+                             NumExs, ExArray, NoReturn, CallConv);
 
   void *InsertPos = 0;
   if (FunctionProtoType *FTP =
index b3010d5e7b5aec348f4d1314e78be6bf5331307b..4e74759676935c78808d5f3127a193d075e2fc56 100644 (file)
@@ -815,7 +815,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
                                 unsigned NumArgs, bool isVariadic,
                                 unsigned TypeQuals, bool hasExceptionSpec,
                                 bool anyExceptionSpec, unsigned NumExceptions,
-                                exception_iterator Exs, bool NoReturn) {
+                                exception_iterator Exs, bool NoReturn,
+                                CallingConv CallConv) {
   ID.AddPointer(Result.getAsOpaquePtr());
   for (unsigned i = 0; i != NumArgs; ++i)
     ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -828,12 +829,14 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
       ID.AddPointer(Exs[i].getAsOpaquePtr());
   }
   ID.AddInteger(NoReturn);
+  ID.AddInteger(CallConv);
 }
 
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
   Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
           getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
-          getNumExceptions(), exception_begin(), getNoReturnAttr());
+          getNumExceptions(), exception_begin(), getNoReturnAttr(),
+          getCallConv());
 }
 
 void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
index 00b74bc21a14a8c877c766a00a3e5223972702ac..597ab37d2ba72bff49f47bd9fd4a1d1eeb8da726 100644 (file)
@@ -271,6 +271,19 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
   
   S += ")";
 
+  switch(T->getCallConv()) {
+  case CC_Default:
+  default: break;
+  case CC_C:
+    S += " __attribute__((cdecl))";
+    break;
+  case CC_X86StdCall:
+    S += " __attribute__((stdcall))";
+    break;
+  case CC_X86FastCall:
+    S += " __attribute__((fastcall))";
+    break;
+  }
   if (T->getNoReturnAttr())
     S += " __attribute__((noreturn))";
 
index 12ce174308a268dbe32a6b7fb67b4587529acedf..19de095b2aa9dbf0442b726e963835e0916f5c58 100644 (file)
@@ -560,7 +560,9 @@ public:
   // Type Analysis / Processing: SemaType.cpp.
   //
   QualType adjustParameterType(QualType T);
-  void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
+  void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL,
+                                bool HandleCallConvAttributes = false,
+                                bool HandleOnlyCallConv = false);
   QualType BuildPointerType(QualType T, unsigned Quals,
                             SourceLocation Loc, DeclarationName Entity);
   QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
index 80831f42c8c7bb000884d81ab2b0552b006aeabd..2e3a4352f2ae98ae71217b9969f7a45ea399326f 100644 (file)
@@ -901,6 +901,14 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
   return Sema::CXXCopyAssignment;
 }
 
+static const char* getCallConvName(CallingConv CC) {
+  switch (CC) {
+  default: return "cdecl";
+  case CC_X86StdCall: return "stdcall";
+  case CC_X86FastCall: return "fastcall";
+  }
+}
+
 /// MergeFunctionDecl - We just parsed a function 'New' from
 /// declarator D which has the same name and scope as a previous
 /// declaration 'Old'.  Figure out how to resolve this situation,
@@ -958,6 +966,33 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
     return true;
   }
 
+  // If a function is first declared with a calling convention, but is
+  // later declared or defined without one, the second decl assumes the
+  // calling convention of the first.
+  //
+  // For the new decl, we have to look at the NON-canonical type to tell the
+  // difference between a function that really doesn't have a calling
+  // convention and one that is declared cdecl. That's because in
+  // canonicalization (see ASTContext.cpp), cdecl is canonicalized away
+  // because it is the default calling convention.
+  //
+  // Note also that we DO NOT return at this point, because we still have
+  // other tests to run.
+  const FunctionType *OldType = OldQType->getAs<FunctionType>();
+  const FunctionType *NewType = New->getType()->getAs<FunctionType>();
+  if (OldType->getCallConv() != CC_Default &&
+      NewType->getCallConv() == CC_Default) {
+    NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
+    New->setType(NewQType);
+    NewQType = Context.getCanonicalType(NewQType);
+  } else if (OldType->getCallConv() != NewType->getCallConv()) {
+    // Calling conventions really aren't compatible, so complain.
+    Diag(New->getLocation(), diag::err_attributes_are_not_compatible)
+      << getCallConvName(NewType->getCallConv())
+      << getCallConvName(OldType->getCallConv());
+    return true;
+  }
+
   if (getLangOptions().CPlusPlus) {
     // (C++98 13.1p2):
     //   Certain function declarations cannot be overloaded:
index a391a0eaed1ca63fdd3541db0a7784d3f978ac43..5e7788ef40fe85f37ae85851b30fb72702aa88f6 100644 (file)
@@ -948,6 +948,12 @@ static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   }
 
   // Attribute can be applied only to functions.
+  // If we try to apply it to a function pointer, don't warn, but don't
+  // do anything, either. All the function-pointer stuff is handled in
+  // SemaType.cpp.
+  ValueDecl *VD = dyn_cast<ValueDecl>(d);
+  if (VD && VD->getType()->isFunctionPointerType())
+    return;
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << 0 /*function*/;
@@ -980,6 +986,11 @@ static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   }
 
   // Attribute can be applied only to functions.
+  // If we try to apply it to a function pointer, don't warn, but don't
+  // do anything, either.
+  ValueDecl *VD = dyn_cast<ValueDecl>(d);
+  if (VD && VD->getType()->isFunctionPointerType())
+    return;
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << 0 /*function*/;
@@ -1019,6 +1030,11 @@ static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
     return;
   }
 
+  // If we try to apply it to a function pointer, don't warn, but don't
+  // do anything, either.
+  ValueDecl *VD = dyn_cast<ValueDecl>(d);
+  if (VD && VD->getType()->isFunctionPointerType())
+    return;
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << 0 /*function*/;
index 906576115a565c4e04a1c82b9e23d70035f1fc1c..8833792494eeeb529670872358ab0582334232a8 100644 (file)
@@ -1241,7 +1241,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
 
     // See if there are any attributes on this declarator chunk.
     if (const AttributeList *AL = DeclType.getAttrs())
-      ProcessTypeAttributeList(T, AL);
+      ProcessTypeAttributeList(T, AL, true);
   }
 
   if (getLangOptions().CPlusPlus && T->isFunctionType()) {
@@ -1274,7 +1274,10 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
   // If there were any type attributes applied to the decl itself (not the
   // type, apply the type attribute to the type!)
   if (const AttributeList *Attrs = D.getAttributes())
-    ProcessTypeAttributeList(T, Attrs);
+    ProcessTypeAttributeList(T, Attrs, true);
+  // Also look in the decl spec.
+  if (const AttributeList *Attrs = D.getDeclSpec().getAttributes())
+    ProcessTypeAttributeList(T, Attrs, true, true);
 
   if (TInfo) {
     if (D.isInvalidType())
@@ -1612,6 +1615,36 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
   Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
 }
 
+/// HandleCDeclTypeAttribute - Process the cdecl attribute on the
+/// specified type.  The attribute contains 0 arguments.
+static void HandleCDeclTypeAttribute(QualType &Type,
+                                     const AttributeList &Attr, Sema &S) {
+  if (Attr.getNumArgs() != 0)
+    return;
+
+  // We only apply this to a pointer to function.
+  if (!Type->isFunctionPointerType()
+      && !Type->isFunctionType())
+    return;
+
+  Type = S.Context.getCallConvType(Type, CC_C);
+}
+
+/// HandleFastCallTypeAttribute - Process the fastcall attribute on the
+/// specified type.  The attribute contains 0 arguments.
+static void HandleFastCallTypeAttribute(QualType &Type,
+                                        const AttributeList &Attr, Sema &S) {
+  if (Attr.getNumArgs() != 0)
+    return;
+
+  // We only apply this to a pointer to function.
+  if (!Type->isFunctionPointerType()
+      && !Type->isFunctionType())
+    return;
+
+  Type = S.Context.getCallConvType(Type, CC_X86FastCall);
+}
+
 /// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the
 /// specified type.  The attribute contains 1 argument, weak or strong.
 static void HandleObjCGCTypeAttribute(QualType &Type,
@@ -1661,6 +1694,21 @@ static void HandleNoReturnTypeAttribute(QualType &Type,
   Type = S.Context.getNoReturnType(Type);
 }
 
+/// HandleStdCallTypeAttribute - Process the stdcall attribute on the
+/// specified type.  The attribute contains 0 arguments.
+static void HandleStdCallTypeAttribute(QualType &Type,
+                                       const AttributeList &Attr, Sema &S) {
+  if (Attr.getNumArgs() != 0)
+    return;
+
+  // We only apply this to a pointer to function.
+  if (!Type->isFunctionPointerType()
+      && !Type->isFunctionType())
+    return;
+
+  Type = S.Context.getCallConvType(Type, CC_X86StdCall);
+}
+
 /// HandleVectorSizeAttribute - this attribute is only applicable to integral
 /// and float scalars, although arrays, pointers, and function return values are
 /// allowed in conjunction with this construct. Aggregates with this attribute
@@ -1708,7 +1756,12 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
   CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
 }
 
-void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
+void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL,
+                                    bool HandleCallConvAttributes,
+                                    bool HandleOnlyCallConv) {
+  if(HandleOnlyCallConv)
+    assert(HandleCallConvAttributes && "Can't not handle call-conv attributes"
+           " while only handling them!");
   // Scan through and apply attributes to this type where it makes sense.  Some
   // attributes (such as __address_space__, __vector_size__, etc) apply to the
   // type, but others can be present in the type specifiers even though they
@@ -1719,16 +1772,32 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
     switch (AL->getKind()) {
     default: break;
     case AttributeList::AT_address_space:
-      HandleAddressSpaceTypeAttribute(Result, *AL, *this);
+      if (!HandleOnlyCallConv)
+        HandleAddressSpaceTypeAttribute(Result, *AL, *this);
+      break;
+    case AttributeList::AT_cdecl:
+      if (HandleCallConvAttributes)
+        HandleCDeclTypeAttribute(Result, *AL, *this);
+      break;
+    case AttributeList::AT_fastcall:
+      if (HandleCallConvAttributes)
+        HandleFastCallTypeAttribute(Result, *AL, *this);
       break;
     case AttributeList::AT_objc_gc:
-      HandleObjCGCTypeAttribute(Result, *AL, *this);
+      if (!HandleOnlyCallConv)
+        HandleObjCGCTypeAttribute(Result, *AL, *this);
       break;
     case AttributeList::AT_noreturn:
-      HandleNoReturnTypeAttribute(Result, *AL, *this);
+      if (!HandleOnlyCallConv)
+        HandleNoReturnTypeAttribute(Result, *AL, *this);
+      break;
+    case AttributeList::AT_stdcall:
+      if (HandleCallConvAttributes)
+        HandleStdCallTypeAttribute(Result, *AL, *this);
       break;
     case AttributeList::AT_vector_size:
-      HandleVectorSizeAttr(Result, *AL, *this);
+      if (!HandleOnlyCallConv)
+        HandleVectorSizeAttr(Result, *AL, *this);
       break;
     }
   }
index a32a4953084d0d1716c82791cd9af59e2020f90d..0337c069f13054ce336f0a12d73ecf481ffad198 100644 (file)
@@ -21,3 +21,15 @@ void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic
 void __attribute__((cdecl)) ctest0() {}
 
 void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{attribute requires 0 argument(s)}}
+
+void (__attribute__((fastcall)) *pfoo)(float*) = foo;
+
+void (__attribute__((stdcall)) *pbar)(float*) = bar;
+
+void (__attribute__((cdecl)) *ptest1)(void) = test1; // expected-warning {{incompatible pointer types}}
+
+void (*pctest0)() = ctest0;
+
+void ctest2() {}
+void (__attribute__((cdecl)) *pctest2)() = ctest2;
+