[cfe-commits] r95291 - in /cfe/trunk: 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

John McCall rjmccall at apple.com
Wed Feb 3 21:44:45 PST 2010


Author: rjmccall
Date: Wed Feb  3 23:44:44 2010
New Revision: 95291

URL: http://llvm.org/viewvc/llvm-project?rev=95291&view=rev
Log:
Allow calling convention attributes to apply to types.  Patch by Chip Davis!



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

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Feb  3 23:44:44 2010
@@ -1766,10 +1766,11 @@
   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 @@
                       bool isVariadic, unsigned TypeQuals,
                       bool hasExceptionSpec, bool anyExceptionSpec,
                       unsigned NumExceptions, exception_iterator Exs,
-                      bool NoReturn);
+                      bool NoReturn, CallingConv CallConv);
 };
 
 

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Feb  3 23:44:44 2010
@@ -1716,7 +1716,7 @@
   // 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 @@
   }
 
   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 @@
   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 =

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed Feb  3 23:44:44 2010
@@ -815,7 +815,8 @@
                                 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 @@
       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,

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Wed Feb  3 23:44:44 2010
@@ -271,6 +271,19 @@
   
   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))";
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb  3 23:44:44 2010
@@ -560,7 +560,9 @@
   // 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,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Feb  3 23:44:44 2010
@@ -901,6 +901,14 @@
   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 @@
     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:

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Feb  3 23:44:44 2010
@@ -948,6 +948,12 @@
   }
 
   // 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 @@
   }
 
   // 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 @@
     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*/;

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Feb  3 23:44:44 2010
@@ -1241,7 +1241,7 @@
 
     // 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 @@
   // 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 @@
   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 @@
   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 @@
   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 @@
     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;
     }
   }

Modified: cfe/trunk/test/Sema/callingconv.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/callingconv.c?rev=95291&r1=95290&r2=95291&view=diff

==============================================================================
--- cfe/trunk/test/Sema/callingconv.c (original)
+++ cfe/trunk/test/Sema/callingconv.c Wed Feb  3 23:44:44 2010
@@ -21,3 +21,15 @@
 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;
+





More information about the cfe-commits mailing list