From 2948d12f92d1d2e22f8c0c639d720cda84d327ef Mon Sep 17 00:00:00 2001 From: Dimitar Dimitrov Date: Sat, 19 Oct 2024 23:40:35 +0300 Subject: [PATCH] pru: Reject bit-fields for TI ABI TI ABI has non-conventional requirements for bit-fields, which cannot be implemented with the current target hooks in GCC. Target hooks are focused on packing and alignment. But PRU uses packed structs by default, and has 1 byte alignment for all types. As an example, this makes it difficult to implement the TI ABI requirement for the following struct to be sized to 4 bytes, per the bit-field type: struct S { int i : 1; } Instead of introducing new target hooks and making risky changes to common GCC code, simply declare bit-fields as not supported in TI ABI mode. PRU is a baremetal target. It has neither support for interrupts nor an RTOS. Hence ABI compatibility is not that critical. I have not seen any projects which rely on ABI compatibility in order to mix object files from GCC and the TI proprietary compiler. The target-specific pass to scan for TI ABI compatibility was rewritten as an IPA pass. This allowed scanning not only of function bodies, but also global variable declarations. Diagnostic locations should now be more accurate. Thus some test cases had to be adjusted. PR target/116205 gcc/ChangeLog: * config/pru/pru-passes.cc (class pass_pru_tiabi_check): Make this an IPA pass. (chkp_type_has_function_pointer): Remove. (check_type_tiabi_compatibility): New function. (chk_function_decl): Rename. (check_function_decl): Simplify. (check_op_callback): Rework to use check_type_tiabi_compatibility. (pass_pru_tiabi_check::execute): Rework to scan all symbols and gimple contents of all defined functions. * config/pru/pru-passes.def (INSERT_PASS_AFTER): Move after pass_ipa_auto_profile_offline. * config/pru/pru-protos.h (make_pru_tiabi_check): New declaration to mark as IPA pass. (make_pru_minrt_check): Specify it is making a gimple pass. * doc/invoke.texi: Document that bit-fields are now rejected for TI ABI. gcc/testsuite/ChangeLog: * gcc.target/pru/mabi-ti-1.c: Adjust diagnostic location. * gcc.target/pru/mabi-ti-2.c: Ditto. * gcc.target/pru/mabi-ti-3.c: Ditto. * gcc.target/pru/mabi-ti-5.c: Ditto. * gcc.target/pru/mabi-ti-6.c: Ditto. * gcc.target/pru/mabi-ti-7.c: Adjust diagnostic locations and add global variables for checking. * gcc.target/pru/mabi-ti-11.c: New test. * gcc.target/pru/mabi-ti-12.c: New test. * gcc.target/pru/mabi-ti-8.c: New test. * gcc.target/pru/mabi-ti-9.c: New test. Signed-off-by: Dimitar Dimitrov --- gcc/config/pru/pru-passes.cc | 189 ++++++++++++++-------- gcc/config/pru/pru-passes.def | 2 +- gcc/config/pru/pru-protos.h | 8 +- gcc/doc/invoke.texi | 23 +++ gcc/testsuite/gcc.target/pru/mabi-ti-1.c | 4 +- gcc/testsuite/gcc.target/pru/mabi-ti-11.c | 14 ++ gcc/testsuite/gcc.target/pru/mabi-ti-12.c | 15 ++ gcc/testsuite/gcc.target/pru/mabi-ti-2.c | 4 +- gcc/testsuite/gcc.target/pru/mabi-ti-3.c | 4 +- gcc/testsuite/gcc.target/pru/mabi-ti-5.c | 10 +- gcc/testsuite/gcc.target/pru/mabi-ti-6.c | 4 +- gcc/testsuite/gcc.target/pru/mabi-ti-7.c | 22 ++- gcc/testsuite/gcc.target/pru/mabi-ti-8.c | 48 ++++++ gcc/testsuite/gcc.target/pru/mabi-ti-9.c | 16 ++ 14 files changed, 274 insertions(+), 89 deletions(-) create mode 100644 gcc/testsuite/gcc.target/pru/mabi-ti-11.c create mode 100644 gcc/testsuite/gcc.target/pru/mabi-ti-12.c create mode 100644 gcc/testsuite/gcc.target/pru/mabi-ti-8.c create mode 100644 gcc/testsuite/gcc.target/pru/mabi-ti-9.c diff --git a/gcc/config/pru/pru-passes.cc b/gcc/config/pru/pru-passes.cc index a763e1ee65ed..ba95bc414412 100644 --- a/gcc/config/pru/pru-passes.cc +++ b/gcc/config/pru/pru-passes.cc @@ -35,6 +35,7 @@ #include "gimple-iterator.h" #include "gimple-walk.h" #include "gimple-expr.h" +#include "cgraph.h" #include "tree-pass.h" #include "pru-protos.h" @@ -46,11 +47,11 @@ namespace { output a conforming code, raise an error. */ const pass_data pass_data_pru_tiabi_check = { - GIMPLE_PASS, /* type */ + SIMPLE_IPA_PASS, /* type */ "*pru_tiabi_check", /* name */ OPTGROUP_NONE, /* optinfo_flags */ TV_NONE, /* tv_id */ - PROP_gimple_any, /* properties_required */ + 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ @@ -58,11 +59,11 @@ const pass_data pass_data_pru_tiabi_check = }; /* Implementation class for the TI ABI compliance-check pass. */ -class pass_pru_tiabi_check : public gimple_opt_pass +class pass_pru_tiabi_check : public simple_ipa_opt_pass { public: pass_pru_tiabi_check (gcc::context *ctxt) - : gimple_opt_pass (pass_data_pru_tiabi_check, ctxt) + : simple_ipa_opt_pass (pass_data_pru_tiabi_check, ctxt) {} /* opt_pass methods: */ @@ -75,54 +76,79 @@ public: }; // class pass_pru_tiabi_check -/* Return 1 if type TYPE is a pointer to function type or a - structure having a pointer to function type as one of its fields. - Otherwise return 0. */ -static bool -chkp_type_has_function_pointer (const_tree type) +/* Issue an error diagnostic if the given TYPE is not compatible with + TI's ABI. */ +static void +check_type_tiabi_compatibility (tree type, location_t loc, + hash_set *visited_nodes) { - bool res = false; + /* Do not visit the same type twice. */ + if (visited_nodes->add (type)) + return; - if (POINTER_TYPE_P (type) && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (type))) - res = true; + if (POINTER_TYPE_P (type)) + { + /* TODO: All declarations and statements share the same object for a + function pointer tree type. So if there are several variables + with the same type (function pointer with same function signature), + only the first declaration would get a diagnostic. */ + if (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (type))) + { + location_t ptrloc = DECL_P (type) ? DECL_SOURCE_LOCATION (type) : loc; + error_at (ptrloc, + "function pointers not supported with %<-mabi=ti%> option"); + } + else + check_type_tiabi_compatibility (TREE_TYPE (type), loc, visited_nodes); + } else if (RECORD_OR_UNION_TYPE_P (type)) { - tree field; - - for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL) - res = res || chkp_type_has_function_pointer (TREE_TYPE (field)); + { + if (DECL_BIT_FIELD (field)) + error_at (DECL_SOURCE_LOCATION (field), + "bit-fields not supported with %<-mabi=ti%> option"); + + check_type_tiabi_compatibility (TREE_TYPE (field), + DECL_SOURCE_LOCATION (field), + visited_nodes); + } } else if (TREE_CODE (type) == ARRAY_TYPE) - res = chkp_type_has_function_pointer (TREE_TYPE (type)); - - return res; + check_type_tiabi_compatibility (TREE_TYPE (type), loc, visited_nodes); } -/* Check the function declaration FNTYPE for TI ABI compatibility. */ +/* Check the GCC function declaration FNTYPE for TI ABI compatibility. */ static void -chk_function_decl (const_tree fntype, location_t call_location) +check_function_decl (tree fntype, location_t loc, + hash_set *visited_nodes) { + /* Do not visit the same type twice. */ + if (visited_nodes->add (fntype)) + return; + /* GCC does not check if the RETURN VALUE pointer is NULL, so do not allow GCC functions with large return values. */ if (!VOID_TYPE_P (TREE_TYPE (fntype)) && pru_return_in_memory (TREE_TYPE (fntype), fntype)) - error_at (call_location, + error_at (loc, "large return values not supported with %<-mabi=ti%> option"); + /* Rest of checks for the returned type. */ + check_type_tiabi_compatibility (TREE_TYPE (fntype), loc, visited_nodes); + /* Check this function's arguments. */ for (tree p = TYPE_ARG_TYPES (fntype); p; p = TREE_CHAIN (p)) - { - tree arg_type = TREE_VALUE (p); - if (chkp_type_has_function_pointer (arg_type)) - error_at (call_location, - "function pointers not supported with %<-mabi=ti%> option"); - } + check_type_tiabi_compatibility (TREE_VALUE (p), loc, visited_nodes); } -/* Callback for walk_gimple_seq that checks TP tree for TI ABI compliance. */ +/* Callback for walk_gimple_seq that checks TP tree for TI ABI compliance. + Note that TP would have been marked as visited before calling + this function. But the underlying type of TP may or may not have + been visited before. */ static tree -check_op_callback (tree *tp, int *walk_subtrees, void *data) +check_op_callback (tree *tp, int *, void *data) { struct walk_stmt_info *wi = (struct walk_stmt_info *) data; @@ -150,66 +176,91 @@ check_op_callback (tree *tp, int *walk_subtrees, void *data) { case FUNCTION_TYPE: case METHOD_TYPE: - { - /* Note: Do not enforce a small return value. It is safe to - call any TI ABI function from GCC, since GCC will - never pass NULL. */ - - /* Check arguments for function pointers. */ - for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p)) - { - tree arg_type = TREE_VALUE (p); - if (chkp_type_has_function_pointer (arg_type)) - error_at (gimple_location (wi->stmt), "function pointers " - "not supported with %<-mabi=ti%> option"); - } - break; - } + { + /* Has this function already been inspected? */ + if (wi->pset->add (type)) + return NULL; + + /* Note: Do not enforce a small return value. It is safe to + call any TI ABI function from GCC, since GCC will + never pass NULL. */ + + /* Check arguments for function pointers. */ + for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p)) + check_type_tiabi_compatibility (TREE_VALUE (p), + gimple_location (wi->stmt), + wi->pset); + break; + } case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: - case POINTER_TYPE: - { - if (chkp_type_has_function_pointer (type)) - { - error_at (gimple_location (wi->stmt), - "function pointers not supported with " - "%<-mabi=ti%> option"); - *walk_subtrees = false; - } - break; - } + { + /* walk_tree would not descend and visit field declarations. + So do it here. */ + check_type_tiabi_compatibility (type, + gimple_location (wi->stmt), + wi->pset); + break; + } default: - break; + break; } return NULL; } /* Pass implementation. */ unsigned -pass_pru_tiabi_check::execute (function *fun) +pass_pru_tiabi_check::execute (function *) { - struct walk_stmt_info wi; - const_tree fntype = TREE_TYPE (fun->decl); + struct cgraph_node *node; + hash_set visited_nodes; + symtab_node *snode; - gimple_seq body = gimple_body (current_function_decl); + FOR_EACH_SYMBOL (snode) + { + tree decl = snode->decl; + if (decl) + { + if (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (decl))) + check_function_decl (TREE_TYPE (decl), + DECL_SOURCE_LOCATION (decl), + &visited_nodes); + else + check_type_tiabi_compatibility (TREE_TYPE (decl), + DECL_SOURCE_LOCATION (decl), + &visited_nodes); + } + } - memset (&wi, 0, sizeof (wi)); - wi.info = NULL; - wi.want_locations = true; + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) + { + function *fn = node->get_fun (); + gimple_stmt_iterator gsi; + basic_block bb; - /* Check the function body. */ - walk_gimple_seq (body, NULL, check_op_callback, &wi); + FOR_EACH_BB_FN (bb, fn) + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + wi.info = NULL; + wi.want_locations = true; - /* Check the function declaration. */ - chk_function_decl (fntype, fun->function_start_locus); + wi.pset = &visited_nodes; + /* Check the function body. */ + walk_gimple_stmt (&gsi, NULL, check_op_callback, &wi); + } + } + } return 0; } } // anon namespace -gimple_opt_pass * +simple_ipa_opt_pass * make_pru_tiabi_check (gcc::context *ctxt) { return new pass_pru_tiabi_check (ctxt); diff --git a/gcc/config/pru/pru-passes.def b/gcc/config/pru/pru-passes.def index da48a2c20989..c0d3528c734f 100644 --- a/gcc/config/pru/pru-passes.def +++ b/gcc/config/pru/pru-passes.def @@ -21,7 +21,7 @@ that the compiled code by GCC conforms to the TI ABI specification. If GCC cannot output a conforming code, then an error is raised. */ -INSERT_PASS_AFTER (pass_warn_unused_result, 1, pru_tiabi_check); +INSERT_PASS_AFTER (pass_ipa_auto_profile_offline, 1, pru_tiabi_check); /* If -minrt option is used, then this pass would validate that the compiled code by GCC is compatible with the minimal diff --git a/gcc/config/pru/pru-protos.h b/gcc/config/pru/pru-protos.h index 4750f0e10077..d2e51ea44d2f 100644 --- a/gcc/config/pru/pru-protos.h +++ b/gcc/config/pru/pru-protos.h @@ -72,8 +72,12 @@ extern int pru_get_ctable_base_offset (HOST_WIDE_INT caddr); extern int pru_symref2ioregno (rtx op); -extern rtl_opt_pass *make_pru_tiabi_check (gcc::context *); -extern rtl_opt_pass *make_pru_minrt_check (gcc::context *); +/* Forward declarations to avoid unnecessarily including headers. */ +class simple_ipa_opt_pass; +class gimple_opt_pass; + +extern simple_ipa_opt_pass *make_pru_tiabi_check (gcc::context *); +extern gimple_opt_pass *make_pru_minrt_check (gcc::context *); #endif /* RTX_CODE */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 26e6e5bea609..2eab5140bc2a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -31367,6 +31367,29 @@ pointer as the first argument of the function. TI ABI, though, mandates that the pointer can be NULL in case the caller is not using the returned value. GNU always passes and expects a valid return value pointer. +@item Size Of Struct Containing Bit-fields +TI ABI mandates that struct size is determined by the bit-field type, if it +contains any. Whereas GNU allocates the smallest amount of bytes which would +fit the bit-field. + +For example, TI ABI reserves 4 bytes for this struct, whereas GNU reserves +a single byte: + +@smallexample +struct S @{ int i:1; @}; +@end smallexample + +@item Access Size For Volatile Bit-fields +TI ABI mandates that volatile bit-fields are accessed using their type. +In contrast, GNU ABI uses the smallest integer type fitting the bit-field. + +For example, TI ABI requires a single load of 4 bytes for the +following bit-field. Whereas GNU generates a load of 1 byte: + +@smallexample +struct S @{ volatile int i:1; @}; +@end smallexample + @end table The current @option{-mabi=ti} implementation simply raises a compile error diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-1.c b/gcc/testsuite/gcc.target/pru/mabi-ti-1.c index 117ae8fd176b..44f5202f3305 100644 --- a/gcc/testsuite/gcc.target/pru/mabi-ti-1.c +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-1.c @@ -4,7 +4,7 @@ /* { dg-options "-O1 -mabi=ti" } */ -int test(int a, int b, void (*fp)(void)) -{ /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ +int test(int a, int b, void (*fp)(void)) /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ +{ return a+b; } diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-11.c b/gcc/testsuite/gcc.target/pru/mabi-ti-11.c new file mode 100644 index 000000000000..c5df2ad39800 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-11.c @@ -0,0 +1,14 @@ +/* Test TI ABI unsupported constructs */ + +/* { dg-do assemble } */ +/* { dg-options "-O1 -mabi=ti" } */ + +struct s1 { + int (*f)(void); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + int a; +}; + +int test1(void) +{ + return ((struct s1 *)0x11223344)->a; +} diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-12.c b/gcc/testsuite/gcc.target/pru/mabi-ti-12.c new file mode 100644 index 000000000000..4658f60b971b --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-12.c @@ -0,0 +1,15 @@ +/* Test TI ABI unsupported constructs */ + +/* { dg-do assemble } */ +/* { dg-options "-O1 -mabi=ti" } */ + +struct s1 { + int (*f)(void); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + int a; +}; + +struct s1 g1; +struct s1 g2; +struct s1 g3; + +int (*g_f1)(char); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-2.c b/gcc/testsuite/gcc.target/pru/mabi-ti-2.c index d4a3aff546c0..66bdfd0aa903 100644 --- a/gcc/testsuite/gcc.target/pru/mabi-ti-2.c +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-2.c @@ -8,8 +8,8 @@ struct big { char c[9]; }; -struct big test(void) -{ /* { dg-error "large return values not supported with '-mabi=ti' option" } */ +struct big test(void) /* { dg-error "large return values not supported with '-mabi=ti' option" } */ +{ static struct big b; return b; } diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-3.c b/gcc/testsuite/gcc.target/pru/mabi-ti-3.c index c49f6653589c..472452b499a3 100644 --- a/gcc/testsuite/gcc.target/pru/mabi-ti-3.c +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-3.c @@ -4,9 +4,9 @@ /* { dg-options "-O1 -mabi=ti" } */ -extern void extfunc(void (*fp)(void)); +extern void extfunc(void (*fp)(void)); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ void test(void) { - extfunc(test); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + extfunc(test); } diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-5.c b/gcc/testsuite/gcc.target/pru/mabi-ti-5.c index 38eeaa4435dc..9ef73b1754c6 100644 --- a/gcc/testsuite/gcc.target/pru/mabi-ti-5.c +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-5.c @@ -4,13 +4,13 @@ /* { dg-options "-O1 -mabi=ti" } */ struct s1 { - void (*f)(void); + void (*f)(void); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ int a; }; struct s2 { union { - void (*f)(void); + void (*f)(int); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ int a; long b; } u; @@ -18,16 +18,16 @@ struct s2 { int test1(struct s1 *p) { - return p->a; /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + return p->a; return 1; } int test1_unused_arg(struct s1 p, int a) -{ /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ +{ return a; } int test2(struct s2 v) -{ /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ +{ return 2; } diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-6.c b/gcc/testsuite/gcc.target/pru/mabi-ti-6.c index c8aa018a21e2..b94971878db9 100644 --- a/gcc/testsuite/gcc.target/pru/mabi-ti-6.c +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-6.c @@ -4,9 +4,9 @@ /* { dg-options "-O1 -mabi=ti" } */ -extern void (*extfuncp)(int); +extern void (*extfuncp)(int); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ void test(void) { - extfuncp(1); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + extfuncp(1); } diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-7.c b/gcc/testsuite/gcc.target/pru/mabi-ti-7.c index cc095facf646..7738255fafac 100644 --- a/gcc/testsuite/gcc.target/pru/mabi-ti-7.c +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-7.c @@ -4,18 +4,32 @@ /* { dg-options "-O1 -mabi=ti" } */ struct s1 { - int (*f)(void); + int (*f)(void); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ int a; }; -extern struct s1 s; +struct s2 { + int (*f)(short); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + int a; +}; + +struct s3 { + int (*f)(char); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + int a; + int b; + int c; +}; + +extern struct s1 g_s1; +extern struct s2 g_s2; +struct s3 g_s3; int test1(void) { - return s.f(); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + return g_s1.f(); } int test2(void) { - return s.a; /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + return g_s2.a; } diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-8.c b/gcc/testsuite/gcc.target/pru/mabi-ti-8.c new file mode 100644 index 000000000000..6f4a91a6b5a6 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-8.c @@ -0,0 +1,48 @@ +/* Test TI ABI unsupported constructs */ + +/* { dg-do assemble } */ +/* { dg-options "-O1 -mabi=ti" } */ + +struct s0 { + int f0 : 2; /* { dg-error "bit-fields not supported with '-mabi=ti' option" } */ + int f1; +}; +struct s0 g_s; + +struct s1 { + int f : 2; /* { dg-error "bit-fields not supported with '-mabi=ti' option" } */ + int a; +}; +struct s1 g_s1; +int test1(void) +{ + struct s1 s; + + return sizeof(s); +} + +struct s2 { + int a2; + int f2 : 3; /* { dg-error "bit-fields not supported with '-mabi=ti' option" } */ +}; +struct s22 { + struct s2 *p; +}; +int test2(struct s22 *s) +{ + return s->p->f2 + s->p->a2; +} + +int test2a(struct s2 *s) +{ + return s->f2 - s->a2; +} + +struct s3 { + int a3; + int f3 : 3; /* { dg-error "bit-fields not supported with '-mabi=ti' option" } */ +}; +int test3(struct s3 s) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/pru/mabi-ti-9.c b/gcc/testsuite/gcc.target/pru/mabi-ti-9.c new file mode 100644 index 000000000000..37c74e0616de --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/mabi-ti-9.c @@ -0,0 +1,16 @@ +/* Test TI ABI unsupported constructs */ + +/* { dg-do assemble } */ +/* { dg-options "-O1 -mabi=ti" } */ + +struct s1 { + int (*f)(void); /* { dg-error "function pointers not supported with '-mabi=ti' option" } */ + int a; +}; + +struct s2 { + struct s1 *s; + int a; +}; + +struct s2 g_s2; -- 2.47.3