[4/8] Add a C++ wrapper for GCC C plug-in

Message ID 20180503184153.31183-5-keiths@redhat.com
State New, archived
Headers

Commit Message

Keith Seitz May 3, 2018, 6:41 p.m. UTC
  This patch introduces a new class which wraps the GCC C compile plug-in.
It is a little unfortunate that this all happened in between the time that
GCC moved to C++ and GDB moved to C++, leaving us with an ABI promise to
support a C-like interface.  The hope is to isolate GDB from some of this
should it change in the future.

Broadly, what this does is replace calls like:

  C_CTX (context)->c_ops->operation (C_CTX (context), ...);

with calls that now look like:

  context->c_plugin->operation (...);

This API will be further refined in following patches when struct
compile_instance/compile_c_instance are changed into classes.

gdb/ChangeLog:

	* Makefile.in (HFILES_NO_SRCDIR): Add compile/gcc-c-plugin.h.
	* compile/compile-c-types.c: Define GCC_METHODN macros and include
	gcc-c-fe.def to define C plugin.
	(delete_instance): Delete `c_plugin'.
	(new_compile_instance): Initialize `c_plugin'.
	* compile/compile-c.h: Include gcc_c_plugin.h.
	(struct compile_c_instance) <c_plugin>: New member.
	* gcc-c-plugin.h: New file.
	Update all callers with API change.
---
 gdb/Makefile.in                 |   1 +
 gdb/compile/compile-c-symbols.c |  30 ++++----
 gdb/compile/compile-c-types.c   | 153 ++++++++++++++++++++++------------------
 gdb/compile/compile-c.h         |   9 ++-
 gdb/compile/gcc-c-plugin.h      |  64 +++++++++++++++++
 5 files changed, 168 insertions(+), 89 deletions(-)
 create mode 100644 gdb/compile/gcc-c-plugin.h
  

Comments

Pedro Alves June 6, 2018, 2:34 p.m. UTC | #1
On 05/03/2018 07:41 PM, Keith Seitz wrote:
> This patch introduces a new class which wraps the GCC C compile plug-in.
> It is a little unfortunate that this all happened in between the time that
> GCC moved to C++ and GDB moved to C++, leaving us with an ABI promise to
> support a C-like interface.  

It's easier to keep an ABI promise in C anyway, so it's not uncommon
for C++ projects to expose a C plugin interface and then provide wrappers
for multiple languages.  That's how the GCC JIT interface is exported
for example.

> The hope is to isolate GDB from some of this
> should it change in the future.

Not so sure it would be a good idea to change it, IMHO.

> 
> Broadly, what this does is replace calls like:
> 
>   C_CTX (context)->c_ops->operation (C_CTX (context), ...);
> 
> with calls that now look like:
> 
>   context->c_plugin->operation (...);

This LGTM.

I do wonder whether c_plugin needs to be a pointer though?

Couldn't it be an object directly?  Like:

  context->c_plugin.operation (...);

I see that the next patch switches this to a method named
plugin(), and then I wonder if that method can return a reference
instead of a pointer (because IIUC, you can never have a
NULL plugin).

TBC, even if you agree, I don't think it's worth it to go
over the pain of to redoing the series because of this.
I'd be totally fine with changing it on top of the series.

> @@ -206,22 +197,20 @@ convert_enum (struct compile_c_instance *context, struct type *type)
>  {
>    gcc_type int_type, result;
>    int i;
> -  struct gcc_c_context *ctx = C_CTX (context);
> +  const gcc_c_plugin *plugin = context->c_plugin;
>  
> -  int_type = ctx->c_ops->int_type_v0 (ctx,
> -				      TYPE_UNSIGNED (type),
> -				      TYPE_LENGTH (type));
> +  int_type = plugin->int_type_v0 (TYPE_UNSIGNED (type),
> +					    TYPE_LENGTH (type));

Alignment looks odd here, but maybe it's just in the email client.

Thanks,
Pedro Alves
  
Keith Seitz July 10, 2018, 4:58 p.m. UTC | #2
On 06/06/2018 07:34 AM, Pedro Alves wrote:
> 
> This LGTM.
> 
> I do wonder whether c_plugin needs to be a pointer though?
> 
> Couldn't it be an object directly?  Like:
> 
>   context->c_plugin.operation (...);
> 
> I see that the next patch switches this to a method named
> plugin(), and then I wonder if that method can return a reference
> instead of a pointer (because IIUC, you can never have a
> NULL plugin).

Yes, I agree. I've changed the plugin method to return a reference instead of a pointer.

> TBC, even if you agree, I don't think it's worth it to go
> over the pain of to redoing the series because of this.
> I'd be totally fine with changing it on top of the series.

It's a trivial change (-> to .), so I've just made the change.

Thanks,
Keith
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 67fff669ba..56883a0acd 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1456,6 +1456,7 @@  HFILES_NO_SRCDIR = \
 	compile/compile-internal.h \
 	compile/compile-object-load.h \
 	compile/compile-object-run.h \
+	compile/gcc-c-plugin.h \
 	config/nm-linux.h \
 	config/nm-nto.h \
 	config/djgpp/langinfo.h \
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index c82e008659..abd829838b 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -161,9 +161,8 @@  convert_one_symbol (struct compile_c_instance *context,
   if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
     {
       /* Binding a tag, so we don't need to build a decl.  */
-      C_CTX (context)->c_ops->tagbind (C_CTX (context),
-				       SYMBOL_NATURAL_NAME (sym.symbol),
-				       sym_type, filename, line);
+      context->c_plugin->tagbind (SYMBOL_NATURAL_NAME (sym.symbol),
+				  sym_type, filename, line);
     }
   else
     {
@@ -196,9 +195,8 @@  convert_one_symbol (struct compile_c_instance *context,
 	      /* Already handled by convert_enum.  */
 	      return;
 	    }
-	  C_CTX (context)->c_ops->build_constant
-	    (C_CTX (context),
-	     sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+	  context->c_plugin->build_constant
+	    (sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
 	     SYMBOL_VALUE (sym.symbol),
 	     filename, line);
 	  return;
@@ -285,15 +283,14 @@  convert_one_symbol (struct compile_c_instance *context,
       if (context->base.scope != COMPILE_I_RAW_SCOPE
 	  || symbol_name == NULL)
 	{
-	  decl = C_CTX (context)->c_ops->build_decl
-	    (C_CTX (context),
-	     SYMBOL_NATURAL_NAME (sym.symbol),
+	  decl = context->c_plugin->build_decl
+	    (SYMBOL_NATURAL_NAME (sym.symbol),
 	     kind,
 	     sym_type,
 	     symbol_name.get (), addr,
 	     filename, line);
 
-	  C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
+	  context->c_plugin->bind (decl, is_global);
 	}
     }
 }
@@ -402,11 +399,10 @@  convert_symbol_bmsym (struct compile_c_instance *context,
     }
 
   sym_type = convert_type (context, type);
-  decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
-					     MSYMBOL_NATURAL_NAME (msym),
-					     kind, sym_type, NULL, addr,
-					     NULL, 0);
-  C_CTX (context)->c_ops->bind (C_CTX (context), decl, 1 /* is_global */);
+  decl = context->c_plugin->build_decl (MSYMBOL_NATURAL_NAME (msym),
+					kind, sym_type, NULL, addr,
+					NULL, 0);
+  context->c_plugin->bind (decl, 1 /* is_global */);
 }
 
 /* See compile-internal.h.  */
@@ -463,7 +459,7 @@  gcc_convert_symbol (void *datum,
 
   CATCH (e, RETURN_MASK_ALL)
     {
-      C_CTX (context)->c_ops->error (C_CTX (context), e.message);
+      context->c_plugin->error (e.message);
     }
   END_CATCH
 
@@ -525,7 +521,7 @@  gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
 
   CATCH (e, RETURN_MASK_ERROR)
     {
-      C_CTX (context)->c_ops->error (C_CTX (context), e.message);
+      context->c_plugin->error (e.message);
     }
   END_CATCH
 
diff --git a/gdb/compile/compile-c-types.c b/gdb/compile/compile-c-types.c
index 46b9f2b3b4..927445208a 100644
--- a/gdb/compile/compile-c-types.c
+++ b/gdb/compile/compile-c-types.c
@@ -99,8 +99,7 @@  convert_pointer (struct compile_c_instance *context, struct type *type)
 {
   gcc_type target = convert_type (context, TYPE_TARGET_TYPE (type));
 
-  return C_CTX (context)->c_ops->build_pointer_type (C_CTX (context),
-						     target);
+  return context->c_plugin->build_pointer_type (target);
 }
 
 /* Convert an array type to its gcc representation.  */
@@ -114,13 +113,11 @@  convert_array (struct compile_c_instance *context, struct type *type)
   element_type = convert_type (context, TYPE_TARGET_TYPE (type));
 
   if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST)
-    return C_CTX (context)->c_ops->error (C_CTX (context),
-					  _("array type with non-constant"
-					    " lower bound is not supported"));
+    return context->c_plugin->error (_("array type with non-constant"
+				       " lower bound is not supported"));
   if (TYPE_LOW_BOUND (range) != 0)
-    return C_CTX (context)->c_ops->error (C_CTX (context),
-					  _("cannot convert array type with "
-					    "non-zero lower bound to C"));
+    return context->c_plugin->error (_("cannot convert array type with "
+				       "non-zero lower bound to C"));
 
   if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
       || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
@@ -128,15 +125,13 @@  convert_array (struct compile_c_instance *context, struct type *type)
       gcc_type result;
 
       if (TYPE_VECTOR (type))
-	return C_CTX (context)->c_ops->error (C_CTX (context),
-					      _("variably-sized vector type"
-						" is not supported"));
+	return context->c_plugin->error (_("variably-sized vector type"
+					   " is not supported"));
 
       std::string upper_bound
 	= c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
-      result = C_CTX (context)->c_ops->build_vla_array_type (C_CTX (context),
-							     element_type,
-							     upper_bound.c_str ());
+      result = context->c_plugin->build_vla_array_type (element_type,
+							upper_bound.c_str ());
       return result;
     }
   else
@@ -152,11 +147,8 @@  convert_array (struct compile_c_instance *context, struct type *type)
 	}
 
       if (TYPE_VECTOR (type))
-	return C_CTX (context)->c_ops->build_vector_type (C_CTX (context),
-							  element_type,
-							  count);
-      return C_CTX (context)->c_ops->build_array_type (C_CTX (context),
-						       element_type, count);
+	return context->c_plugin->build_vector_type (element_type, count);
+      return context->c_plugin->build_array_type (element_type, count);
     }
 }
 
@@ -171,11 +163,11 @@  convert_struct_or_union (struct compile_c_instance *context, struct type *type)
   /* First we create the resulting type and enter it into our hash
      table.  This lets recursive types work.  */
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
-    result = C_CTX (context)->c_ops->build_record_type (C_CTX (context));
+    result = context->c_plugin->build_record_type ();
   else
     {
       gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
-      result = C_CTX (context)->c_ops->build_union_type (C_CTX (context));
+      result = context->c_plugin->build_union_type ();
     }
   insert_type (context, type, result);
 
@@ -187,15 +179,14 @@  convert_struct_or_union (struct compile_c_instance *context, struct type *type)
       field_type = convert_type (context, TYPE_FIELD_TYPE (type, i));
       if (bitsize == 0)
 	bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
-      C_CTX (context)->c_ops->build_add_field (C_CTX (context), result,
-					       TYPE_FIELD_NAME (type, i),
-					       field_type,
-					       bitsize,
-					       TYPE_FIELD_BITPOS (type, i));
+      context->c_plugin->build_add_field (result,
+					  TYPE_FIELD_NAME (type, i),
+					  field_type,
+					  bitsize,
+					  TYPE_FIELD_BITPOS (type, i));
     }
 
-  C_CTX (context)->c_ops->finish_record_or_union (C_CTX (context), result,
-						  TYPE_LENGTH (type));
+  context->c_plugin->finish_record_or_union (result, TYPE_LENGTH (type));
   return result;
 }
 
@@ -206,22 +197,20 @@  convert_enum (struct compile_c_instance *context, struct type *type)
 {
   gcc_type int_type, result;
   int i;
-  struct gcc_c_context *ctx = C_CTX (context);
+  const gcc_c_plugin *plugin = context->c_plugin;
 
-  int_type = ctx->c_ops->int_type_v0 (ctx,
-				      TYPE_UNSIGNED (type),
-				      TYPE_LENGTH (type));
+  int_type = plugin->int_type_v0 (TYPE_UNSIGNED (type),
+					    TYPE_LENGTH (type));
 
-  result = ctx->c_ops->build_enum_type (ctx, int_type);
+  result = plugin->build_enum_type (int_type);
   for (i = 0; i < TYPE_NFIELDS (type); ++i)
     {
-      ctx->c_ops->build_add_enum_constant (ctx,
-					   result,
-					   TYPE_FIELD_NAME (type, i),
-					   TYPE_FIELD_ENUMVAL (type, i));
+      plugin->build_add_enum_constant (result,
+				       TYPE_FIELD_NAME (type, i),
+				       TYPE_FIELD_ENUMVAL (type, i));
     }
 
-  ctx->c_ops->finish_enum_type (ctx, result);
+  plugin->finish_enum_type (result);
 
   return result;
 }
@@ -261,9 +250,8 @@  convert_func (struct compile_c_instance *context, struct type *type)
   for (i = 0; i < TYPE_NFIELDS (type); ++i)
     array.elements[i] = convert_type (context, TYPE_FIELD_TYPE (type, i));
 
-  result = C_CTX (context)->c_ops->build_function_type (C_CTX (context),
-							return_type,
-							&array, is_varargs);
+  result = context->c_plugin->build_function_type (return_type,
+						   &array, is_varargs);
   xfree (array.elements);
 
   return result;
@@ -274,22 +262,20 @@  convert_func (struct compile_c_instance *context, struct type *type)
 static gcc_type
 convert_int (struct compile_c_instance *context, struct type *type)
 {
-  if (C_CTX (context)->c_ops->c_version >= GCC_C_FE_VERSION_1)
+  if (context->c_plugin->version () >= GCC_C_FE_VERSION_1)
     {
       if (TYPE_NOSIGN (type))
 	{
 	  gdb_assert (TYPE_LENGTH (type) == 1);
-	  return C_CTX (context)->c_ops->char_type (C_CTX (context));
+	  return context->c_plugin->char_type ();
 	}
-      return C_CTX (context)->c_ops->int_type (C_CTX (context),
-					       TYPE_UNSIGNED (type),
-					       TYPE_LENGTH (type),
-					       TYPE_NAME (type));
+      return context->c_plugin->int_type (TYPE_UNSIGNED (type),
+					  TYPE_LENGTH (type),
+					  TYPE_NAME (type));
     }
   else
-    return C_CTX (context)->c_ops->int_type_v0 (C_CTX (context),
-						TYPE_UNSIGNED (type),
-						TYPE_LENGTH (type));
+    return context->c_plugin->int_type_v0 (TYPE_UNSIGNED (type),
+					   TYPE_LENGTH (type));
 }
 
 /* Convert a floating-point type to its gcc representation.  */
@@ -297,13 +283,11 @@  convert_int (struct compile_c_instance *context, struct type *type)
 static gcc_type
 convert_float (struct compile_c_instance *context, struct type *type)
 {
-  if (C_CTX (context)->c_ops->c_version >= GCC_C_FE_VERSION_1)
-    return C_CTX (context)->c_ops->float_type (C_CTX (context),
-					       TYPE_LENGTH (type),
-					       TYPE_NAME (type));
+  if (context->c_plugin->version () >= GCC_C_FE_VERSION_1)
+    return context->c_plugin->float_type (TYPE_LENGTH (type),
+					  TYPE_NAME (type));
   else
-    return C_CTX (context)->c_ops->float_type_v0 (C_CTX (context),
-						  TYPE_LENGTH (type));
+    return context->c_plugin->float_type_v0 (TYPE_LENGTH (type));
 }
 
 /* Convert the 'void' type to its gcc representation.  */
@@ -311,7 +295,7 @@  convert_float (struct compile_c_instance *context, struct type *type)
 static gcc_type
 convert_void (struct compile_c_instance *context, struct type *type)
 {
-  return C_CTX (context)->c_ops->void_type (C_CTX (context));
+  return context->c_plugin->void_type ();
 }
 
 /* Convert a boolean type to its gcc representation.  */
@@ -319,7 +303,7 @@  convert_void (struct compile_c_instance *context, struct type *type)
 static gcc_type
 convert_bool (struct compile_c_instance *context, struct type *type)
 {
-  return C_CTX (context)->c_ops->bool_type (C_CTX (context));
+  return context->c_plugin->bool_type ();
 }
 
 /* Convert a qualified type to its gcc representation.  */
@@ -340,9 +324,7 @@  convert_qualified (struct compile_c_instance *context, struct type *type)
   if (TYPE_RESTRICT (type))
     quals |= GCC_QUALIFIER_RESTRICT;
 
-  return C_CTX (context)->c_ops->build_qualified_type (C_CTX (context),
-						       unqual_converted,
-						       quals);
+  return context->c_plugin->build_qualified_type (unqual_converted, quals);
 }
 
 /* Convert a complex type to its gcc representation.  */
@@ -352,7 +334,7 @@  convert_complex (struct compile_c_instance *context, struct type *type)
 {
   gcc_type base = convert_type (context, TYPE_TARGET_TYPE (type));
 
-  return C_CTX (context)->c_ops->build_complex_type (C_CTX (context), base);
+  return context->c_plugin->build_complex_type (base);
 }
 
 /* A helper function which knows how to convert most types from their
@@ -419,9 +401,7 @@  convert_type_basic (struct compile_c_instance *context, struct type *type)
       }
     }
 
-  return C_CTX (context)->c_ops->error (C_CTX (context),
-					_("cannot convert gdb type "
-					  "to gcc type"));
+  return context->c_plugin->error (_("cannot convert gdb type to gcc type"));
 }
 
 /* See compile-internal.h.  */
@@ -456,6 +436,7 @@  delete_instance (struct compile_instance *c)
   struct compile_c_instance *context = (struct compile_c_instance *) c;
 
   context->base.fe->ops->destroy (context->base.fe);
+  delete context->c_plugin;
   htab_delete (context->type_map);
   if (context->symbol_err_map != NULL)
     htab_delete (context->symbol_err_map);
@@ -481,8 +462,46 @@  new_compile_instance (struct gcc_c_context *fe)
 					eq_type_map_instance,
 					xfree, xcalloc, xfree);
 
-  fe->c_ops->set_callbacks (fe, gcc_convert_symbol,
-			    gcc_symbol_address, result);
+  result->c_plugin = new gcc_c_plugin (fe);
+
+  result->c_plugin->set_callbacks (gcc_convert_symbol, gcc_symbol_address,
+				   result);
 
   return &result->base;
 }
+
+/* C plug-in wrapper.  */
+
+#define FORWARD(OP,...) m_context->c_ops->OP(m_context, ##__VA_ARGS__)
+#define GCC_METHOD0(R, N) \
+  R gcc_c_plugin::N () const \
+  { return FORWARD (N); }
+#define GCC_METHOD1(R, N, A) \
+  R gcc_c_plugin::N (A a) const \
+  { return FORWARD (N, a); }
+#define GCC_METHOD2(R, N, A, B) \
+  R gcc_c_plugin::N (A a, B b) const \
+  { return FORWARD (N, a, b); }
+#define GCC_METHOD3(R, N, A, B, C) \
+  R gcc_c_plugin::N (A a, B b, C c)  const \
+  { return FORWARD (N, a, b, c); }
+#define GCC_METHOD4(R, N, A, B, C, D) \
+  R gcc_c_plugin::N (A a, B b, C c, D d) const \
+  { return FORWARD (N, a, b, c, d); }
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+  R gcc_c_plugin::N (A a, B b, C c, D d, E e) const \
+  { return FORWARD (N, a, b, c, d, e); }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+  R gcc_c_plugin::N (A a, B b, C c, D d, E e, F f, G g) const \
+  { return FORWARD (N, a, b, c, d, e, f, g); }
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+#undef FORWARD
diff --git a/gdb/compile/compile-c.h b/gdb/compile/compile-c.h
index cff2aef906..ffa58021e2 100644
--- a/gdb/compile/compile-c.h
+++ b/gdb/compile/compile-c.h
@@ -18,6 +18,7 @@ 
 #define GDB_COMPILE_C_H
 
 #include "common/enum-flags.h"
+#include "gcc-c-plugin.h"
 #include "hashtab.h"
 
 /* enum-flags wrapper.  */
@@ -46,12 +47,10 @@  struct compile_c_instance
 
   /* Map from gdb symbols to gcc error messages to emit.  */
   htab_t symbol_err_map;
-};
-
-/* A helper macro that takes a compile_c_instance and returns its
-   corresponding gcc_c_context.  */
 
-#define C_CTX(I) ((struct gcc_c_context *) ((I)->base.fe))
+  /* GCC C plugin.  */
+  gcc_c_plugin *c_plugin;
+};
 
 /* Emit code to compute the address for all the local variables in
    scope at PC in BLOCK.  Returns a malloc'd vector, indexed by gdb
diff --git a/gdb/compile/gcc-c-plugin.h b/gdb/compile/gcc-c-plugin.h
new file mode 100644
index 0000000000..12d422f6aa
--- /dev/null
+++ b/gdb/compile/gcc-c-plugin.h
@@ -0,0 +1,64 @@ 
+/* GCC C plug-in wrapper for GDB.
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* A class representing the C plug-in.  */
+
+class gcc_c_plugin
+{
+public:
+
+  explicit gcc_c_plugin (struct gcc_c_context *gcc_c)
+    : m_context (gcc_c)
+  {
+  }
+
+  /* Set the oracle callbacks to be used by the compiler plug-in.  */
+  void set_callbacks (gcc_c_oracle_function *binding_oracle,
+		      gcc_c_symbol_address_function *address_oracle,
+		      void *datum)
+  {
+    m_context->c_ops->set_callbacks (m_context, binding_oracle,
+				     address_oracle, datum);
+  }
+
+  /* Returns the interface version of the compiler plug-in.  */
+  int version () const { return m_context->c_ops->c_version; }
+
+#define GCC_METHOD0(R, N) R N () const;
+#define GCC_METHOD1(R, N, A) R N (A) const;
+#define GCC_METHOD2(R, N, A, B) R N (A, B) const;
+#define GCC_METHOD3(R, N, A, B, C) R N (A, B, C) const;
+#define GCC_METHOD4(R, N, A, B, C, D) R N (A, B, C, D) const;
+#define GCC_METHOD5(R, N, A, B, C, D, E) R N (A, B, C, D, E) const;
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) R N (A, B, C, D, E, F, G) const;
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+private:
+  /* The GCC C context.  */
+  struct gcc_c_context *m_context;
+};