diff mbox

[Ada] Use C++-compatible calling convention on x86/Windows

Message ID 201205191129.23652.ebotcazou@adacore.com
State New
Headers show

Commit Message

Eric Botcazou May 19, 2012, 9:29 a.m. UTC
This changes the calling convention of primitive operations on x86/Windows (the 
equivalent of C++ methods) in order to be compatible with C++, which changed 
the calling convention in order to be compatible with MSVC++.

Tested on i686-pc-mingw32, applied on the mainline and 4.7 branch.


2012-05-19  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/decl.c (Has_Thiscall_Convention): New macro.
	(gnat_to_gnu_entity) <E_Subprogram_Type>: Test it to set the thiscall
	calling convention
	(get_minimal_subprog_decl): Likewise.
	(gnat_first_param_is_class): New predicate.

Comments

Eric Botcazou June 13, 2012, 1:31 p.m. UTC | #1
> Tested on i686-pc-mingw32, applied on the mainline and 4.7 branch.
>
>
> 2012-05-19  Eric Botcazou  <ebotcazou@adacore.com>
>
> 	* gcc-interface/decl.c (Has_Thiscall_Convention): New macro.
> 	(gnat_to_gnu_entity) <E_Subprogram_Type>: Test it to set the thiscall
> 	calling convention
> 	(get_minimal_subprog_decl): Likewise.
> 	(gnat_first_param_is_class): New predicate.

Now reverted, including on the 4.7 branch (this is only for x86/Windows).  We 
have decided to use another approach to deal with the problem as the above one 
introduces backwards compatibily issues.
diff mbox

Patch

Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 187675)
+++ gcc-interface/decl.c	(working copy)
@@ -50,19 +50,23 @@ 
 #include "ada-tree.h"
 #include "gigi.h"
 
-/* Convention_Stdcall should be processed in a specific way on 32 bits
-   Windows targets only.  The macro below is a helper to avoid having to
-   check for a Windows specific attribute throughout this unit.  */
+/* "stdcall" and "thiscall" conventions should be processed in a specific way
+   on 32-bit x86/Windows only.  The macros below are helpers to avoid having
+   to check for a Windows specific attribute throughout this unit.  */
 
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
 #ifdef TARGET_64BIT
 #define Has_Stdcall_Convention(E) \
   (!TARGET_64BIT && Convention (E) == Convention_Stdcall)
+#define Has_Thiscall_Convention(E) \
+  (!TARGET_64BIT && gnat_first_param_is_class (E))
 #else
 #define Has_Stdcall_Convention(E) (Convention (E) == Convention_Stdcall)
+#define Has_Thiscall_Convention(E) (gnat_first_param_is_class (E))
 #endif
 #else
 #define Has_Stdcall_Convention(E) 0
+#define Has_Thiscall_Convention(E) 0
 #endif
 
 /* Stack realignment is necessary for functions with foreign conventions when
@@ -126,6 +130,7 @@  DEF_VEC_ALLOC_O(variant_desc,heap);
 static GTY ((if_marked ("tree_int_map_marked_p"),
 	     param_is (struct tree_int_map))) htab_t annotate_value_cache;
 
+static bool gnat_first_param_is_class (Entity_Id) ATTRIBUTE_UNUSED;
 static bool allocatable_size_p (tree, bool);
 static void prepend_one_attribute_to (struct attrib **,
 				      enum attr_type, tree, tree, Node_Id);
@@ -4403,6 +4408,11 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	    (&attr_list, ATTR_MACHINE_ATTRIBUTE,
 	     get_identifier ("stdcall"), NULL_TREE,
 	     gnat_entity);
+	else if (Has_Thiscall_Convention (gnat_entity))
+	  prepend_one_attribute_to
+	    (&attr_list, ATTR_MACHINE_ATTRIBUTE,
+	     get_identifier ("thiscall"), NULL_TREE,
+	     gnat_entity);
 
 	/* If we should request stack realignment for a foreign convention
 	   subprogram, do so.  Note that this applies to task entry points in
@@ -5266,6 +5276,10 @@  get_minimal_subprog_decl (Entity_Id gnat
     prepend_one_attribute_to (&attr_list, ATTR_MACHINE_ATTRIBUTE,
 			      get_identifier ("stdcall"), NULL_TREE,
 			      gnat_entity);
+  else if (Has_Thiscall_Convention (gnat_entity))
+    prepend_one_attribute_to (&attr_list, ATTR_MACHINE_ATTRIBUTE,
+			      get_identifier ("thiscall"), NULL_TREE,
+			      gnat_entity);
 
   if (No (Interface_Name (gnat_entity)) && gnu_ext_name == gnu_entity_name)
     gnu_ext_name = NULL_TREE;
@@ -5275,6 +5289,63 @@  get_minimal_subprog_decl (Entity_Id gnat
 			 false, true, true, true, attr_list, gnat_entity);
 }
 
+/* Return whether the E_Subprogram_Type/E_Function/E_Procedure GNAT_ENTITY has
+   a first parameter with a class or equivalent type.
+
+   We use the predicate on 32-bit x86/Windows to find out whether we need to
+   use the "thiscall" calling convention for GNAT_ENTITY.  This convention is
+   the one set for C++ methods (functions with METHOD_TYPE) by the back-end.
+   Now in Ada primitive operations are regular subprograms (e.g. you can have
+   common pointers to both) so we cannot compute an equivalent of METHOD_TYPE
+   and so we set the calling convention in an uniform way.  */
+
+static bool
+gnat_first_param_is_class (Entity_Id gnat_entity)
+{
+  Entity_Id gnat_param = First_Formal_With_Extras (gnat_entity);
+  Entity_Id gnat_type;
+  Node_Id node;
+
+  if (No (gnat_param))
+    return false;
+
+  gnat_type = Underlying_Type (Etype (gnat_param));
+
+  /* This is the main case.  Note that we must return the same value for
+     regular tagged types and CW types since dispatching calls have a CW
+     type on the caller side and a tagged type on the callee side.  */
+  if (Is_Tagged_Type (gnat_type))
+    return True;
+
+  /* C++ classes with no virtual functions can be imported as limited
+     record types, but we need to return true for the constructors.  */
+  if (Is_CPP_Class (gnat_type))
+    return True;
+
+  /* The language-level "protected" calling convention doesn't distinguish
+     tagged protected types from non-tagged protected types (e.g. you can
+     have common pointers to both) so we must use a single low-level calling
+     convention for it.  Since tagged protected types can be derived from
+     simple limited interfaces, we need to pick the calling convention of
+     the latters.  */
+  if (Is_Protected_Record_Type (gnat_type))
+    return True;
+
+  /* If this is the special E_Subprogram_Type built for the declaration of
+     an access to protected subprogram type, the first parameter will have
+     type Address, but we must return true to be consistent with above.  */
+  if (Is_Itype (gnat_entity)
+      && Present (node = Associated_Node_For_Itype (gnat_entity))
+      && Nkind (node) == N_Full_Type_Declaration
+      && Ekind (Defining_Identifier (node)) == E_Access_Subprogram_Type
+      && Present (node = Original_Access_Type (Defining_Identifier (node)))
+      && (Ekind (node) == E_Access_Protected_Subprogram_Type
+	  || Ekind (node) == E_Anonymous_Access_Protected_Subprogram_Type))
+    return True;
+
+  return False;
+}
+
 /* Finalize the processing of From_With_Type incomplete types.  */
 
 void