Attribute copy can be invoked with an expression argument to copy from
the expression's type.  However, it must avoid passing the expression
as the last (optional) argument to decl_attributes because the function
is only prepared to deal with DECLs and types.

The attached patch passes null as the last argument in these situations
instead.  In addition, it makes more robust the handling of expressions
of pointers to function type (a subtle bug here was exposed by testing
of additional cases beyond the one in the report).

Tested on x86_64-linux.  I plan to commit the patch in the next day or
so unless there are concerns/suggestions.

Martin
PR c++/94346 - [9/10 Regression] ICE due to handle_copy_attribute since r9-3982

gcc/c-family/ChangeLog:

	PR c++/94346
	* c-attribs.c (handle_copy_attribute): Avoid passing expressions
	to decl_attributes.  Make handling of different kinds of entities
	more robust.
	
gcc/c-c++-common/ChangeLog:

	PR c++/94346
	* c-c++-common/attr-copy.c: New test.

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index f30158a258b..93e740853a9 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -2526,17 +2526,21 @@ handle_copy_attribute (tree *node, tree name, tree args,
       && !FUNCTION_POINTER_TYPE_P (TREE_TYPE (ref)))
     ref = TREE_TYPE (ref);
 
+  tree reftype = DECL_P (ref) || EXPR_P (ref) ? TREE_TYPE (ref) : ref;
+
   if (DECL_P (decl))
     {
       if ((VAR_P (decl)
 	   && (TREE_CODE (ref) == FUNCTION_DECL
 	       || (EXPR_P (ref)
-		   && POINTER_TYPE_P (TREE_TYPE (ref))
-		   && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (ref))))))
+		   && POINTER_TYPE_P (reftype)
+		   && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype)))))
 	  || (TREE_CODE (decl) == FUNCTION_DECL
 	      && (VAR_P (ref)
 		  || (EXPR_P (ref)
-		      && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (ref))))))
+		      && !FUNC_OR_METHOD_TYPE_P (reftype)
+		      && (!POINTER_TYPE_P (reftype)
+			  || !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype)))))))
 	{
 	  /* It makes no sense to try to copy function attributes
 	     to a variable, or variable attributes to a function.  */
@@ -2606,15 +2610,11 @@ handle_copy_attribute (tree *node, tree name, tree args,
 
   /* Similarly, a function declared with attribute noreturn has it
      attached on to it, but a C11 _Noreturn function does not.  */
-  tree reftype = ref;
   if (DECL_P (ref)
       && TREE_THIS_VOLATILE (ref)
-      && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype)))
+      && FUNC_OR_METHOD_TYPE_P (reftype))
     TREE_THIS_VOLATILE (decl) = true;
 
-  if (DECL_P (ref) || EXPR_P (ref))
-    reftype = TREE_TYPE (ref);
-
   if (POINTER_TYPE_P (reftype))
     reftype = TREE_TYPE (reftype);
 
@@ -2623,9 +2623,10 @@ handle_copy_attribute (tree *node, tree name, tree args,
 
   tree attrs = TYPE_ATTRIBUTES (reftype);
 
-  /* Copy type attributes from REF to DECL.  */
+  /* Copy type attributes from REF to DECL.  Pass in REF if it's a DECL
+     or a type but not if it's an expression.  */
   for (tree at = attrs; at; at = TREE_CHAIN (at))
-    decl_attributes (node, at, flags, ref);
+    decl_attributes (node, at, flags, EXPR_P (ref) ? NULL_TREE : ref);
 
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/c-c++-common/attr-copy.c b/gcc/testsuite/c-c++-common/attr-copy.c
new file mode 100644
index 00000000000..284088a8b97
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-copy.c
@@ -0,0 +1,43 @@
+/* PR c++/94346 - ICE due to handle_copy_attribute
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+#if __cplusplus > 199711L
+#  define SA(expr) static_assert (expr, #expr)
+#elif __cplusplus
+#  define SA(expr)							\
+  typedef __attribute__ ((unused)) char Assert[!(expr) ? -1 : 1]
+#else
+#  define SA(expr) _Static_assert (expr, #expr)
+#endif
+
+typedef struct ATTR (packed) A { ATTR (packed) unsigned bf: 1; } A;
+
+int bar (void);
+
+struct C
+{
+  char c;
+  ATTR (copy ((bar (), ((struct A *)(0))[0]))) int i;
+};
+
+/* Verify the attribute has been copied.  */
+SA (__builtin_offsetof (struct C, i) == 1);
+
+
+
+/* Verify attribute copy can copy from the type a comma expression.  */
+ATTR (alloc_size (1)) void* alloc1 (int);
+
+ATTR (copy ((bar (), alloc1))) void* alloc2 (int, int);
+
+ATTR (copy ((bar (), alloc1))) void alloc3 (int);  /* { dg-warning "'alloc_size' attribute ignored on a function returning 'void'" } */
+
+
+typedef ATTR (alloc_size (1)) void* F (int);
+
+ATTR (copy ((bar (), (F*)0))) void* alloc4 (int, int);
+
+ATTR (copy ((bar (), (F*)0))) void alloc5 (int, int);  /* { dg-warning "'alloc_size' attribute ignored on a function returning 'void'" } */

Reply via email to