aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gcc-interface/decl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/gcc-interface/decl.c')
-rw-r--r--gcc/ada/gcc-interface/decl.c81
1 files changed, 69 insertions, 12 deletions
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 18ec63d..b493e80 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -6,7 +6,7 @@
* *
* C Implementation File *
* *
- * Copyright (C) 1992-2016, Free Software Foundation, Inc. *
+ * Copyright (C) 1992-2017, Free Software Foundation, Inc. *
* *
* GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- *
@@ -34,6 +34,7 @@
#include "fold-const.h"
#include "stor-layout.h"
#include "tree-inline.h"
+#include "demangle.h"
#include "ada.h"
#include "types.h"
@@ -5093,10 +5094,6 @@ get_unpadded_type (Entity_Id gnat_entity)
bool
is_cplusplus_method (Entity_Id gnat_entity)
{
- /* Check that the subprogram has C++ convention. */
- if (Convention (gnat_entity) != Convention_CPP)
- return false;
-
/* A constructor is a method on the C++ side. We deal with it now because
it is declared without the 'this' parameter in the sources and, although
the front-end will create a version with the 'this' parameter for code
@@ -5104,6 +5101,10 @@ is_cplusplus_method (Entity_Id gnat_entity)
if (Is_Constructor (gnat_entity))
return true;
+ /* Check that the subprogram has C++ convention. */
+ if (Convention (gnat_entity) != Convention_CPP)
+ return false;
+
/* And that the type of the first parameter (indirectly) has it too. */
Entity_Id gnat_first = First_Formal (gnat_entity);
if (No (gnat_first))
@@ -5115,19 +5116,75 @@ is_cplusplus_method (Entity_Id gnat_entity)
if (Convention (gnat_type) != Convention_CPP)
return false;
- /* This is the main case: C++ method imported as a primitive operation.
- Note that a C++ class with no virtual functions can be imported as a
- limited record type so the operation is not necessarily dispatching. */
- if (Is_Primitive (gnat_entity))
+ /* This is the main case: a C++ virtual method imported as a primitive
+ operation of a tagged type. */
+ if (Is_Dispatching_Operation (gnat_entity))
+ return true;
+
+ /* This is set on the E_Subprogram_Type built for a dispatching call. */
+ if (Is_Dispatch_Table_Entity (gnat_entity))
return true;
/* A thunk needs to be handled like its associated primitive operation. */
if (Is_Subprogram (gnat_entity) && Is_Thunk (gnat_entity))
return true;
- /* This is set on the E_Subprogram_Type built for a dispatching call. */
- if (Is_Dispatch_Table_Entity (gnat_entity))
- return true;
+ /* Now on to the annoying case: a C++ non-virtual method, imported either
+ as a non-primitive operation of a tagged type or as a primitive operation
+ of an untagged type. We cannot reliably differentiate these cases from
+ their static member or regular function equivalents in Ada, so we ask
+ the C++ side through the mangled name of the function, as the implicit
+ 'this' parameter is not encoded in the mangled name of a method. */
+ if (Is_Subprogram (gnat_entity) && Present (Interface_Name (gnat_entity)))
+ {
+ String_Pointer sp = { NULL, NULL };
+ Get_External_Name (gnat_entity, false, sp);
+
+ void *mem;
+ struct demangle_component *cmp
+ = cplus_demangle_v3_components (Name_Buffer,
+ DMGL_GNU_V3
+ | DMGL_TYPES
+ | DMGL_PARAMS
+ | DMGL_RET_DROP,
+ &mem);
+ if (!cmp)
+ return false;
+
+ /* We need to release MEM once we have a successful demangling. */
+ bool ret = false;
+
+ if (cmp->type == DEMANGLE_COMPONENT_TYPED_NAME
+ && cmp->u.s_binary.right->type == DEMANGLE_COMPONENT_FUNCTION_TYPE
+ && (cmp = cmp->u.s_binary.right->u.s_binary.right) != NULL
+ && cmp->type == DEMANGLE_COMPONENT_ARGLIST)
+ {
+ /* Make sure there is at least one parameter in C++ too. */
+ if (cmp->u.s_binary.left)
+ {
+ unsigned int n_ada_args = 0;
+ do {
+ n_ada_args++;
+ gnat_first = Next_Formal (gnat_first);
+ } while (Present (gnat_first));
+
+ unsigned int n_cpp_args = 0;
+ do {
+ n_cpp_args++;
+ cmp = cmp->u.s_binary.right;
+ } while (cmp);
+
+ if (n_cpp_args < n_ada_args)
+ ret = true;
+ }
+ else
+ ret = true;
+ }
+
+ free (mem);
+
+ return ret;
+ }
return false;
}