d: Merge UDAs between function prototype and definitions (PR90136)
authorIain Buclaw <ibuclaw@gdcproject.org>
Thu, 18 Apr 2019 07:50:56 +0000 (09:50 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Tue, 31 Mar 2020 22:12:47 +0000 (00:12 +0200)
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.

gcc/d/ChangeLog
gcc/d/d-attribs.cc
gcc/d/d-tree.h
gcc/d/decl.cc
gcc/d/modules.cc
gcc/d/typeinfo.cc
gcc/d/types.cc
gcc/testsuite/ChangeLog
gcc/testsuite/gdc.dg/pr90136a.d [new file with mode: 0644]
gcc/testsuite/gdc.dg/pr90136b.d [new file with mode: 0644]
gcc/testsuite/gdc.dg/pr90136c.d [new file with mode: 0644]

index 20817e38fc69fbe9f51dee1e487bdd2cf254de10..d27f83e77d474db756635d740656769ae1c11b5c 100644 (file)
@@ -1,3 +1,25 @@
+2020-04-01  Iain Buclaw  <ibuclaw@gdcproject.org>
+
+       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  <ibuclaw@gdcproject.org>
 
        * d-attribs.cc (d_langhook_common_attribute_table): Add always_inline.
index bba6f516ea359a5f8c2cee13ec8b4d9d7c9e04cf..69434c639e7b4f6d73100ea33f95aeb90d26fc27 100644 (file)
@@ -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
index 0f831c754c042003932fef9d1ae79f3d281417e1..89feb9e7010e8d4d4c6fac2da72b46e0a994f8a5 100644 (file)
@@ -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  */
index 053d5537f4e6ce46e56f8e52c46b882f541b2abd..042c10c2943128e3f9f6e854350692a7b123618f 100644 (file)
@@ -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;
index ba18f2cabc14ca818b4674c14b7a2ba33bbec5f9..4f541905a94a99d5753252154cf2a7c7515e16e3 100644 (file)
@@ -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;
 }
index 90a44944f4ce6fbe71328621ad0bad8e0093be5d..6aa4f64a7131559f0a4aac8376753eac506a76a3 100644 (file)
@@ -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;
 }
index 025285205ebfdce4aa9bdb5b00780de8d7c2f908..e0e770af325d914c503b81f43fcdf03149810b33 100644 (file)
@@ -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))
index 220789ffe1e537e483b03e96d670d922bce613a5..adfbdb01af77f955a18f96ac628a32e79002b18e 100644 (file)
@@ -1,3 +1,10 @@
+2020-04-01  Iain Buclaw  <ibuclaw@gdcproject.org>
+
+       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  <andrea.corallo@arm.com>
 
        * 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 (file)
index 0000000..e623b23
--- /dev/null
@@ -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 (file)
index 0000000..f1f9b0a
--- /dev/null
@@ -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 (file)
index 0000000..cf1c5de
--- /dev/null
@@ -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 }