From: Iain Buclaw Date: Thu, 18 Apr 2019 07:50:56 +0000 (+0200) Subject: d: Merge UDAs between function prototype and definitions (PR90136) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=013fca64fc17ba646c3564eab52fac50f0751188;p=gcc.git d: Merge UDAs between function prototype and definitions (PR90136) This change fixes the symbol merging in get_symbol_decl to also consider prototypes. This allows the ability to set user defined attributes on the prototype of a function, which then get applied to the definition, if found later in the compilation. The lowering of UDAs to GCC attributes has been commonized into a single function called apply_user_attributes. gcc/d/ChangeLog: PR d/90136 * d-attribs.cc: Include dmd/attrib.h. (build_attributes): Redeclare as static. (apply_user_attributes): New function. * d-tree.h (class UserAttributeDeclaration): Remove. (build_attributes): Remove. (apply_user_attributes): Declare. (finish_aggregate_type): Remove attrs argument. * decl.cc (get_symbol_decl): Merge declaration prototypes with definitions. Use apply_user_attributes. * modules.cc (layout_moduleinfo_fields): Remove last argument to finish_aggregate_type. * typeinfo.cc (layout_classinfo_interfaces): Likewise. * types.cc (layout_aggregate_members): Likewise. (finish_aggregate_type): Remove attrs argument. (TypeVisitor::visit (TypeEnum *)): Use apply_user_attributes. (TypeVisitor::visit (TypeStruct *)): Remove last argument to finish_aggregate_type. Use apply_user_attributes. (TypeVisitor::visit (TypeClass *)): Likewise. gcc/testsuite/ChangeLog: PR d/90136 * gdc.dg/pr90136a.d: New test. * gdc.dg/pr90136b.d: New test. * gdc.dg/pr90136c.d: New test. --- diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 20817e38fc6..d27f83e77d4 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,25 @@ +2020-04-01 Iain Buclaw + + PR d/90136 + * d-attribs.cc: Include dmd/attrib.h. + (build_attributes): Redeclare as static. + (apply_user_attributes): New function. + * d-tree.h (class UserAttributeDeclaration): Remove. + (build_attributes): Remove. + (apply_user_attributes): Declare. + (finish_aggregate_type): Remove attrs argument. + * decl.cc (get_symbol_decl): Merge declaration prototypes with + definitions. Use apply_user_attributes. + * modules.cc (layout_moduleinfo_fields): Remove last argument to + finish_aggregate_type. + * typeinfo.cc (layout_classinfo_interfaces): Likewise. + * types.cc (layout_aggregate_members): Likewise. + (finish_aggregate_type): Remove attrs argument. + (TypeVisitor::visit (TypeEnum *)): Use apply_user_attributes. + (TypeVisitor::visit (TypeStruct *)): Remove last argument to + finish_aggregate_type. Use apply_user_attributes. + (TypeVisitor::visit (TypeClass *)): Likewise. + 2020-03-31 Iain Buclaw * d-attribs.cc (d_langhook_common_attribute_table): Add always_inline. diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index bba6f516ea3..69434c639e7 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" +#include "dmd/attrib.h" #include "dmd/declaration.h" #include "dmd/mtype.h" @@ -234,7 +235,7 @@ uda_attribute_p (const char *name) `gcc.attribute.Attribute'. This symbol is internally recognized by the compiler and maps them to their equivalent GCC attribute. */ -tree +static tree build_attributes (Expressions *eattrs) { if (!eattrs) @@ -319,6 +320,30 @@ build_attributes (Expressions *eattrs) return attribs; } +/* If any GCC attributes are found in the declaration SYM, apply them to the + type or decl NODE. */ + +void +apply_user_attributes (Dsymbol *sym, tree node) +{ + if (!sym->userAttribDecl) + { + if (DECL_P (node) && DECL_ATTRIBUTES (node) != NULL) + decl_attributes (&node, DECL_ATTRIBUTES (node), 0); + + return; + } + + location_t saved_location = input_location; + input_location = make_location_t (sym->loc); + + Expressions *attrs = sym->userAttribDecl->getAttributes (); + decl_attributes (&node, build_attributes (attrs), + TYPE_P (node) ? ATTR_FLAG_TYPE_IN_PLACE : 0); + + input_location = saved_location; +} + /* Built-in attribute handlers. */ /* Handle a "noreturn" attribute; arguments as in diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index 0f831c754c0..89feb9e7010 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -29,7 +29,6 @@ class FuncDeclaration; class StructDeclaration; class TypeInfoDeclaration; class VarDeclaration; -class UserAttributeDeclaration; class Expression; class ClassReferenceExp; class Module; @@ -485,7 +484,7 @@ extern bool doing_semantic_analysis_p; /* In d-attribs.c. */ extern tree insert_type_attribute (tree, const char *, tree = NULL_TREE); extern tree insert_decl_attribute (tree, const char *, tree = NULL_TREE); -extern tree build_attributes (Expressions *); +extern void apply_user_attributes (Dsymbol *, tree); /* In d-builtins.cc. */ extern const attribute_spec d_langhook_attribute_table[]; @@ -681,8 +680,7 @@ extern tree make_array_type (Type *, unsigned HOST_WIDE_INT); extern tree make_struct_type (const char *, int n, ...); extern tree insert_type_modifiers (tree, unsigned); extern void insert_aggregate_field (tree, tree, size_t); -extern void finish_aggregate_type (unsigned, unsigned, tree, - UserAttributeDeclaration *); +extern void finish_aggregate_type (unsigned, unsigned, tree); extern tree build_ctype (Type *); #endif /* GCC_D_TREE_H */ diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 053d5537f4e..042c10c2943 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1110,7 +1110,10 @@ get_symbol_decl (Declaration *decl) /* Set function type afterwards as there could be self references. */ TREE_TYPE (decl->csym) = build_ctype (fd->type); - if (!fd->fbody) + /* Set DECL_INITIAL now if the function has a definition. */ + if (fd->fbody) + DECL_INITIAL (decl->csym) = error_mark_node; + else DECL_EXTERNAL (decl->csym) = 1; } else @@ -1151,26 +1154,38 @@ get_symbol_decl (Declaration *decl) mangled_name); /* The frontend doesn't handle duplicate definitions of unused symbols with the same mangle. So a check is done here instead. */ - if (!DECL_EXTERNAL (decl->csym)) + if (IDENTIFIER_DSYMBOL (mangled_name)) { - if (IDENTIFIER_DSYMBOL (mangled_name)) - { - Declaration *other = IDENTIFIER_DSYMBOL (mangled_name); + Declaration *other = IDENTIFIER_DSYMBOL (mangled_name); + tree olddecl = decl->csym; + decl->csym = get_symbol_decl (other); - /* Non-templated variables shouldn't be defined twice. */ - if (!decl->isInstantiated ()) - ScopeDsymbol::multiplyDefined (decl->loc, decl, other); - - decl->csym = get_symbol_decl (other); + /* The current declaration is a prototype or marked extern, merge + applied user attributes and return. */ + if (DECL_EXTERNAL (olddecl) && !DECL_INITIAL (olddecl)) + { + apply_user_attributes (decl, decl->csym); return decl->csym; } - + /* The previous declaration is a prototype or marked extern, set the + current declaration as the main reference of the symbol. */ + else if (DECL_EXTERNAL (decl->csym) && !DECL_INITIAL (decl->csym)) + { + IDENTIFIER_DSYMBOL (mangled_name) = decl; + DECL_EXTERNAL (decl->csym) = 0; + } + /* Non-extern, non-templated decls shouldn't be defined twice. */ + else if (!decl->isInstantiated ()) + ScopeDsymbol::multiplyDefined (decl->loc, decl, other); + } + else + { IDENTIFIER_PRETTY_NAME (mangled_name) = get_identifier (decl->toPrettyChars (true)); IDENTIFIER_DSYMBOL (mangled_name) = decl; - } - SET_DECL_ASSEMBLER_NAME (decl->csym, mangled_name); + SET_DECL_ASSEMBLER_NAME (decl->csym, mangled_name); + } } DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (decl); @@ -1358,13 +1373,7 @@ get_symbol_decl (Declaration *decl) } /* Apply any user attributes that may affect semantic meaning. */ - if (decl->userAttribDecl) - { - Expressions *attrs = decl->userAttribDecl->getAttributes (); - decl_attributes (&decl->csym, build_attributes (attrs), 0); - } - else if (DECL_ATTRIBUTES (decl->csym) != NULL) - decl_attributes (&decl->csym, DECL_ATTRIBUTES (decl->csym), 0); + apply_user_attributes (decl, decl->csym); /* %% Probably should be a little more intelligent about setting this. */ TREE_USED (decl->csym) = 1; diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index ba18f2cabc1..4f541905a94 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -543,7 +543,7 @@ layout_moduleinfo_fields (Module *decl, tree type) size_t alignsize = MAX (TYPE_ALIGN_UNIT (type), TYPE_ALIGN_UNIT (ptr_type_node)); - finish_aggregate_type (offset, alignsize, type, NULL); + finish_aggregate_type (offset, alignsize, type); return type; } diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 90a44944f4c..6aa4f64a713 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -1254,7 +1254,7 @@ layout_classinfo_interfaces (ClassDeclaration *decl) /* Update the type size and record mode for the classinfo type. */ if (type != tinfo_types[TK_CLASSINFO_TYPE]) - finish_aggregate_type (structsize, TYPE_ALIGN_UNIT (type), type, NULL); + finish_aggregate_type (structsize, TYPE_ALIGN_UNIT (type), type); return type; } diff --git a/gcc/d/types.cc b/gcc/d/types.cc index 025285205eb..e0e770af325 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -352,8 +352,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) tree offset = size_int (ad->anonoffset); fixup_anonymous_offset (TYPE_FIELDS (type), offset); - finish_aggregate_type (ad->anonstructsize, ad->anonalignsize, - type, NULL); + finish_aggregate_type (ad->anonstructsize, ad->anonalignsize, type); /* And make the corresponding data member. */ tree field = create_field_decl (type, NULL, 0, 0); @@ -462,19 +461,8 @@ layout_aggregate_type (AggregateDeclaration *decl, tree type, the finalized record mode. */ void -finish_aggregate_type (unsigned structsize, unsigned alignsize, - tree type, UserAttributeDeclaration *attrs) +finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type) { - TYPE_SIZE (type) = NULL_TREE; - - /* Write out any GCC attributes that were applied to the type declaration. */ - if (attrs) - { - Expressions *eattrs = attrs->getAttributes (); - decl_attributes (&type, build_attributes (eattrs), - ATTR_FLAG_TYPE_IN_PLACE); - } - /* Set size and alignment as requested by frontend. */ TYPE_SIZE (type) = bitsize_int (structsize * BITS_PER_UNIT); TYPE_SIZE_UNIT (type) = size_int (structsize); @@ -878,12 +866,7 @@ public: build_type_decl (t->ctype, t->sym); } - if (t->sym->userAttribDecl) - { - Expressions *eattrs = t->sym->userAttribDecl->getAttributes (); - decl_attributes (&t->ctype, build_attributes (eattrs), - ATTR_FLAG_TYPE_IN_PLACE); - } + apply_user_attributes (t->sym, t->ctype); } /* Build a struct or union type. Layout should be exactly represented @@ -922,8 +905,8 @@ public: /* Put out all fields. */ layout_aggregate_type (t->sym, t->ctype, t->sym); - finish_aggregate_type (structsize, alignsize, t->ctype, - t->sym->userAttribDecl); + apply_user_attributes (t->sym, t->ctype); + finish_aggregate_type (structsize, alignsize, t->ctype); } TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym); @@ -965,8 +948,8 @@ public: /* Put out all fields, including from each base class. */ layout_aggregate_type (t->sym, basetype, t->sym); - finish_aggregate_type (t->sym->structsize, t->sym->alignsize, - basetype, t->sym->userAttribDecl); + apply_user_attributes (t->sym, basetype); + finish_aggregate_type (t->sym->structsize, t->sym->alignsize, basetype); /* Classes only live in memory, so always set the TREE_ADDRESSABLE bit. */ for (tree tv = basetype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 220789ffe1e..adfbdb01af7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2020-04-01 Iain Buclaw + + PR d/90136 + * gdc.dg/pr90136a.d: New test. + * gdc.dg/pr90136b.d: New test. + * gdc.dg/pr90136c.d: New test. + 2020-03-31 Andrea Corallo * jit.dg/test-version.c: New testcase. diff --git a/gcc/testsuite/gdc.dg/pr90136a.d b/gcc/testsuite/gdc.dg/pr90136a.d new file mode 100644 index 00000000000..e623b230f28 --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr90136a.d @@ -0,0 +1,21 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93038 +// { dg-do compile } +// { dg-options "-fdump-tree-optimized" } +// { dg-final { scan-tree-dump-times "sum_array \\(array\\)" 0 "optimized"} } + +import gcc.attribute; + +@attribute("forceinline") int sum_array(int[] input); + +int sum_array(int[] input) +{ + int sum = 0; + foreach (elem; input) + sum += elem; + return sum; +} + +int test(int[] array) +{ + return sum_array(array); +} diff --git a/gcc/testsuite/gdc.dg/pr90136b.d b/gcc/testsuite/gdc.dg/pr90136b.d new file mode 100644 index 00000000000..f1f9b0a8e6e --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr90136b.d @@ -0,0 +1,21 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93038 +// { dg-do compile } +// { dg-options "-fdump-tree-optimized" } +// { dg-final { scan-tree-dump-times "sum_array \\(array\\)" 1 "optimized"} } + +import gcc.attribute; + +@attribute("noinline") int sum_array(int[] input); + +int sum_array(int[] input) +{ + int sum = 0; + foreach (elem; input) + sum += elem; + return sum; +} + +int test(int[] array) +{ + return sum_array(array); +} diff --git a/gcc/testsuite/gdc.dg/pr90136c.d b/gcc/testsuite/gdc.dg/pr90136c.d new file mode 100644 index 00000000000..cf1c5de645e --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr90136c.d @@ -0,0 +1,9 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93038 +// { dg-do compile } +// { dg-options "-Wattributes" } + +import gcc.attribute; + +@attribute("forceinline") int sum_array(int[] input); +@attribute("noinline") int sum_array(int[] input); +// { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .forceinline." "" { target *-*-* } .-1 }