[PATCH] Add a simulate_record_decl lang hook
Richard Sandiford
richard.sandiford@arm.com
Sat Oct 30 18:29:12 GMT 2021
Jason Merrill <jason@redhat.com> writes:
> On 10/18/21 16:35, Richard Sandiford wrote:
>> Jason Merrill <jason@redhat.com> writes:
>>> On 9/24/21 13:53, Richard Sandiford wrote:
>>>> + if (type == error_mark_node)
>>>> + return lhd_simulate_record_decl (loc, name, fields);
>>>
>>> Why fall back to the language-independent function on error? Is there a
>>> case where that gives better error recovery than just returning
>>> error_mark_node?
>>
>> I don't think falling back necessarily improves future error messages
>> (or makes them worse). The reason was more that the code to handle
>> target builtins generally expects to be able to create whatever types
>> and functions it wants. If we return something unexpected, even it's
>> error_mark_node, then there's a higher risk of ICEs later on.
>>
>> I guess that's a bit defeatist. But in practice, the first code
>> that uses the hook will be code that previously ran at start-up
>> and so didn't have to worry about these errors.
>>
>> In practice I think errors will be extremely rare.
>>
>>>> + xref_basetypes (type, NULL_TREE);
>>>> + type = begin_class_definition (type);
>>>> + if (type == error_mark_node)
>>>> + return lhd_simulate_record_decl (loc, name, fields);
>>>> +
>>>> + for (tree field : fields)
>>>> + finish_member_declaration (field);
>>>> +
>>>> + type = finish_struct (type, NULL_TREE);
>>>> +
>>>> + tree decl = build_decl (loc, TYPE_DECL, ident, type);
>>>> + TYPE_NAME (type) = decl;
>>>> + TYPE_STUB_DECL (type) = decl;
>>>
>>> Setting TYPE_NAME and TYPE_STUB_DECL to the typedef is wrong; it should
>>> work to just remove these two lines. I expect they're also wrong for C.
>>>
>>> For C++ only, I wonder if you need this typedef at all.
>>>
>>> If you do want it, you need to use set_underlying_type to create a real
>>> typedef. I expect that's also true for C.
>>
>> Ah, yeah, thanks for the pointer. Fixed in the patch below.
>>
>> I wanted the hook to simulate the typedef even for C++ because its
>> first user will be arm_neon.h. The spec for arm_neon.h says that the
>> types must be declared as:
>>
>> typedef struct int32x2x4_t { … } int32x2x4_t;
>>
>> etc. So, although it's a silly edge case, code that tries to take
>> advantage of the struct stat hack, such as:
>>
>> #include <arm_neon.h>
>> struct int32x2x4_t int32x2x4_t = {};
>>
>> should continue to be rejected for C++ as well as C.
>>
>> Maybe in future we could add a flag to suppress the typedef if some
>> callers prefer that behaviour.
>>
>> Tested as before.
>
> Can the C++ hook go in cp-lang.c (which already includes
> langhooks-def.h) instead of decl.c? With that change, the patch is OK
> in a week if nobody else has feedback.
Thanks. I just tried with that change, but it breaks Objective C++ builds,
since cp-lang.o isn't linked there.
Richard
>
>> gcc/
>> * langhooks.h (lang_hooks_for_types::simulate_record_decl): New hook.
>> * langhooks-def.h (lhd_simulate_record_decl): Declare.
>> (LANG_HOOKS_SIMULATE_RECORD_DECL): Define.
>> (LANG_HOOKS_FOR_TYPES_INITIALIZER): Include it.
>> * langhooks.c (lhd_simulate_record_decl): New function.
>>
>> gcc/c/
>> * c-tree.h (c_simulate_record_decl): Declare.
>> * c-objc-common.h (LANG_HOOKS_SIMULATE_RECORD_DECL): Override.
>> * c-decl.c (c_simulate_record_decl): New function.
>>
>> gcc/cp/
>> * decl.c: Include langhooks-def.h.
>> (cxx_simulate_record_decl): New function.
>> * cp-objcp-common.h (cxx_simulate_record_decl): Declare.
>> (LANG_HOOKS_SIMULATE_RECORD_DECL): Override.
>> ---
>> gcc/c/c-decl.c | 30 ++++++++++++++++++++++++++++++
>> gcc/c/c-objc-common.h | 2 ++
>> gcc/c/c-tree.h | 2 ++
>> gcc/cp/cp-objcp-common.h | 4 ++++
>> gcc/cp/decl.c | 37 +++++++++++++++++++++++++++++++++++++
>> gcc/langhooks-def.h | 4 ++++
>> gcc/langhooks.c | 19 +++++++++++++++++++
>> gcc/langhooks.h | 10 ++++++++++
>> 8 files changed, 108 insertions(+)
>>
>> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
>> index 771efa3eadf..186fa1692c1 100644
>> --- a/gcc/c/c-decl.c
>> +++ b/gcc/c/c-decl.c
>> @@ -9436,6 +9436,36 @@ c_simulate_enum_decl (location_t loc, const char *name,
>> input_location = saved_loc;
>> return enumtype;
>> }
>> +
>> +/* Implement LANG_HOOKS_SIMULATE_RECORD_DECL. */
>> +
>> +tree
>> +c_simulate_record_decl (location_t loc, const char *name,
>> + array_slice<const tree> fields)
>> +{
>> + location_t saved_loc = input_location;
>> + input_location = loc;
>> +
>> + class c_struct_parse_info *struct_info;
>> + tree ident = get_identifier (name);
>> + tree type = start_struct (loc, RECORD_TYPE, ident, &struct_info);
>> +
>> + for (unsigned int i = 0; i < fields.size (); ++i)
>> + {
>> + DECL_FIELD_CONTEXT (fields[i]) = type;
>> + if (i > 0)
>> + DECL_CHAIN (fields[i - 1]) = fields[i];
>> + }
>> +
>> + finish_struct (loc, type, fields[0], NULL_TREE, struct_info);
>> +
>> + tree decl = build_decl (loc, TYPE_DECL, ident, type);
>> + set_underlying_type (decl);
>> + lang_hooks.decls.pushdecl (decl);
>> +
>> + input_location = saved_loc;
>> + return type;
>> +}
>>
>> /* Create the FUNCTION_DECL for a function definition.
>> DECLSPECS, DECLARATOR and ATTRIBUTES are the parts of
>> diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
>> index 7d35a0621e4..f4e8271f06c 100644
>> --- a/gcc/c/c-objc-common.h
>> +++ b/gcc/c/c-objc-common.h
>> @@ -81,6 +81,8 @@ along with GCC; see the file COPYING3. If not see
>>
>> #undef LANG_HOOKS_SIMULATE_ENUM_DECL
>> #define LANG_HOOKS_SIMULATE_ENUM_DECL c_simulate_enum_decl
>> +#undef LANG_HOOKS_SIMULATE_RECORD_DECL
>> +#define LANG_HOOKS_SIMULATE_RECORD_DECL c_simulate_record_decl
>> #undef LANG_HOOKS_TYPE_FOR_MODE
>> #define LANG_HOOKS_TYPE_FOR_MODE c_common_type_for_mode
>> #undef LANG_HOOKS_TYPE_FOR_SIZE
>> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
>> index a046c6b0926..f1dbbd5d573 100644
>> --- a/gcc/c/c-tree.h
>> +++ b/gcc/c/c-tree.h
>> @@ -598,6 +598,8 @@ extern tree finish_struct (location_t, tree, tree, tree,
>> class c_struct_parse_info *);
>> extern tree c_simulate_enum_decl (location_t, const char *,
>> vec<string_int_pair> *);
>> +extern tree c_simulate_record_decl (location_t, const char *,
>> + array_slice<const tree>);
>> extern struct c_arg_info *build_arg_info (void);
>> extern struct c_arg_info *get_parm_info (bool, tree);
>> extern tree grokfield (location_t, struct c_declarator *,
>> diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
>> index f1704aad557..d5859406e8f 100644
>> --- a/gcc/cp/cp-objcp-common.h
>> +++ b/gcc/cp/cp-objcp-common.h
>> @@ -39,6 +39,8 @@ extern bool cp_handle_option (size_t, const char *, HOST_WIDE_INT, int,
>> extern tree cxx_make_type_hook (tree_code);
>> extern tree cxx_simulate_enum_decl (location_t, const char *,
>> vec<string_int_pair> *);
>> +extern tree cxx_simulate_record_decl (location_t, const char *,
>> + array_slice<const tree>);
>>
>> /* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks
>> specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c,
>> @@ -139,6 +141,8 @@ extern tree cxx_simulate_enum_decl (location_t, const char *,
>> #define LANG_HOOKS_MAKE_TYPE cxx_make_type_hook
>> #undef LANG_HOOKS_SIMULATE_ENUM_DECL
>> #define LANG_HOOKS_SIMULATE_ENUM_DECL cxx_simulate_enum_decl
>> +#undef LANG_HOOKS_SIMULATE_RECORD_DECL
>> +#define LANG_HOOKS_SIMULATE_RECORD_DECL cxx_simulate_record_decl
>> #undef LANG_HOOKS_TYPE_FOR_MODE
>> #define LANG_HOOKS_TYPE_FOR_MODE c_common_type_for_mode
>> #undef LANG_HOOKS_TYPE_FOR_SIZE
>> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
>> index 561debe6a0e..db8ec90fef1 100644
>> --- a/gcc/cp/decl.c
>> +++ b/gcc/cp/decl.c
>> @@ -57,6 +57,7 @@ along with GCC; see the file COPYING3. If not see
>> #include "omp-general.h"
>> #include "omp-offload.h" /* For offload_vars. */
>> #include "opts.h"
>> +#include "langhooks-def.h" /* For lhd_simulate_record_decl */
>>
>> /* Possible cases of bad specifiers type used by bad_specifiers. */
>> enum bad_spec_place {
>> @@ -16601,6 +16602,42 @@ cxx_simulate_enum_decl (location_t loc, const char *name,
>> input_location = saved_loc;
>> return enumtype;
>> }
>> +
>> +/* Implement LANG_HOOKS_SIMULATE_RECORD_DECL. */
>> +
>> +tree
>> +cxx_simulate_record_decl (location_t loc, const char *name,
>> + array_slice<const tree> fields)
>> +{
>> + iloc_sentinel ils (loc);
>> +
>> + tree ident = get_identifier (name);
>> + tree type = xref_tag (/*tag_code=*/record_type, ident);
>> + if (type != error_mark_node
>> + && (TREE_CODE (type) != RECORD_TYPE || COMPLETE_TYPE_P (type)))
>> + {
>> + error ("redefinition of %q#T", type);
>> + type = error_mark_node;
>> + }
>> + if (type == error_mark_node)
>> + return lhd_simulate_record_decl (loc, name, fields);
>> +
>> + xref_basetypes (type, NULL_TREE);
>> + type = begin_class_definition (type);
>> + if (type == error_mark_node)
>> + return lhd_simulate_record_decl (loc, name, fields);
>> +
>> + for (tree field : fields)
>> + finish_member_declaration (field);
>> +
>> + type = finish_struct (type, NULL_TREE);
>> +
>> + tree decl = build_decl (loc, TYPE_DECL, ident, type);
>> + set_underlying_type (decl);
>> + lang_hooks.decls.pushdecl (decl);
>> +
>> + return type;
>> +}
>>
>> /* We're defining DECL. Make sure that its type is OK. */
>>
>> diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
>> index 02b4681dd96..5f17620aaeb 100644
>> --- a/gcc/langhooks-def.h
>> +++ b/gcc/langhooks-def.h
>> @@ -56,6 +56,8 @@ extern void lhd_overwrite_decl_assembler_name (tree decl, tree name);
>> extern bool lhd_warn_unused_global_decl (const_tree);
>> extern tree lhd_simulate_enum_decl (location_t, const char *,
>> vec<string_int_pair> *);
>> +extern tree lhd_simulate_record_decl (location_t, const char *,
>> + array_slice<const tree>);
>> extern tree lhd_type_for_size (unsigned precision, int unsignedp);
>> extern void lhd_incomplete_type_error (location_t, const_tree, const_tree);
>> extern tree lhd_type_promotes_to (tree);
>> @@ -183,6 +185,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
>>
>> #define LANG_HOOKS_MAKE_TYPE lhd_make_node
>> #define LANG_HOOKS_SIMULATE_ENUM_DECL lhd_simulate_enum_decl
>> +#define LANG_HOOKS_SIMULATE_RECORD_DECL lhd_simulate_record_decl
>> #define LANG_HOOKS_CLASSIFY_RECORD NULL
>> #define LANG_HOOKS_TYPE_FOR_SIZE lhd_type_for_size
>> #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR lhd_incomplete_type_error
>> @@ -217,6 +220,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
>> #define LANG_HOOKS_FOR_TYPES_INITIALIZER { \
>> LANG_HOOKS_MAKE_TYPE, \
>> LANG_HOOKS_SIMULATE_ENUM_DECL, \
>> + LANG_HOOKS_SIMULATE_RECORD_DECL, \
>> LANG_HOOKS_CLASSIFY_RECORD, \
>> LANG_HOOKS_TYPE_FOR_MODE, \
>> LANG_HOOKS_TYPE_FOR_SIZE, \
>> diff --git a/gcc/langhooks.c b/gcc/langhooks.c
>> index 48c72377778..49613b42077 100644
>> --- a/gcc/langhooks.c
>> +++ b/gcc/langhooks.c
>> @@ -516,6 +516,25 @@ lhd_simulate_enum_decl (location_t loc, const char *name,
>> return enumtype;
>> }
>>
>> +/* Default implementation of LANG_HOOKS_SIMULATE_RECORD_DECL.
>> + Just create a normal RECORD_TYPE and a TYPE_DECL for it. */
>> +tree
>> +lhd_simulate_record_decl (location_t loc, const char *name,
>> + array_slice<const tree> fields)
>> +{
>> + for (unsigned int i = 1; i < fields.size (); ++i)
>> + /* Reversed by finish_builtin_struct. */
>> + DECL_CHAIN (fields[i]) = fields[i - 1];
>> +
>> + tree type = lang_hooks.types.make_type (RECORD_TYPE);
>> + finish_builtin_struct (type, name, fields.back (), NULL_TREE);
>> +
>> + tree decl = build_decl (loc, TYPE_DECL, get_identifier (name), type);
>> + lang_hooks.decls.pushdecl (decl);
>> +
>> + return type;
>> +}
>> +
>> /* Default implementation of LANG_HOOKS_TYPE_FOR_SIZE.
>> Return an integer type with PRECISION bits of precision,
>> that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
>> diff --git a/gcc/langhooks.h b/gcc/langhooks.h
>> index ffd3e0bf2db..3e89134e8b4 100644
>> --- a/gcc/langhooks.h
>> +++ b/gcc/langhooks.h
>> @@ -68,6 +68,16 @@ struct lang_hooks_for_types
>> them all with the given source location. */
>> tree (*simulate_enum_decl) (location_t, const char *, vec<string_int_pair> *);
>>
>> + /* Do the equivalent of:
>> +
>> + typedef struct NAME { FIELDS; } NAME;
>> +
>> + associating it with location LOC. Return the associated RECORD_TYPE.
>> +
>> + FIELDS is a list of FIELD_DECLs, in layout order. */
>> + tree (*simulate_record_decl) (location_t loc, const char *name,
>> + array_slice<const tree> fields);
>> +
>> /* Return what kind of RECORD_TYPE this is, mainly for purposes of
>> debug information. If not defined, record types are assumed to
>> be structures. */
>>
More information about the Gcc-patches
mailing list