diff mbox

Fix TYPE_MAIN_VARIANT construction for arrays of qualified typedefs (PR c/68162)

Message ID alpine.DEB.2.10.1512021824170.17734@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers Dec. 2, 2015, 6:24 p.m. UTC
PR c/68162 reports a spurious warning about incompatible types
involving arrays of const double, constructed in one place using a
typedef for const double and in another place literally using const
double.

The problem is that the array of the typedef was incorrectly
constructed without a TYPE_MAIN_VARIANT being an array of unqualified
elements as it should be (though it seems some more recent change
resulted in this producing incorrect diagnostics, likely the support
for C++-style handling of arrays of qualified type).  This patch fixes
the logic in grokdeclarator to determine first_non_attr_kind, which is
used to determine whether it is necessary to use the TYPE_MAIN_VARIANT
of the type in the declaration specifiers.

However, fixing that logic introduces a failure of
gcc.dg/debug/dwarf2/pr47939-4.c, a test introduced along with
first_non_attr_kind.  Thus, it is necessary to track the original
qualified typedef when qualifying an array type, to use it rather than
a newly-constructed type, to avoid regressing regarding typedef names
in debug info.  This is done along lines I suggested in
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47939#c6>: track the
original type and the number of levels of array indirection at which
it appears, and, in possibly affected cases, pass extra arguments to
c_build_qualified_type (with default arguments to avoid needing to
pass those extra arguments explicitly everywhere).  Given Richard's
recent fix to dwarf2out.c, this allows the C bug to be fixed without
causing debug information regressions.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.  Applied to 
mainline.

gcc/c:
2015-12-02  Joseph Myers  <joseph@codesourcery.com>

	PR c/68162
	* c-decl.c (grokdeclarator): Set first_non_attr_kind before
	following link from declarator to next declarator.  Track original
	qualified type and pass it to c_build_qualified_type.
	* c-typeck.c (c_build_qualified_type): Add arguments
	orig_qual_type and orig_qual_indirect.

gcc/c-family:
2015-12-02  Joseph Myers  <joseph@codesourcery.com>

	PR c/68162
	* c-common.h (c_build_qualified_type): Add extra default
	arguments.

gcc/cp:
2015-12-02  Joseph Myers  <joseph@codesourcery.com>

	PR c/68162
	* tree.c (c_build_qualified_type): Add extra arguments.

gcc/testsuite:
2015-12-02  Joseph Myers  <joseph@codesourcery.com>

	PR c/68162
	* gcc.dg/pr68162-1.c: New test.
diff mbox

Patch

Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 231075)
+++ gcc/c/c-decl.c	(working copy)
@@ -5351,6 +5351,8 @@  grokdeclarator (const struct c_declarator *declara
   tree returned_attrs = NULL_TREE;
   bool bitfield = width != NULL;
   tree element_type;
+  tree orig_qual_type = NULL;
+  size_t orig_qual_indirect = 0;
   struct c_arg_info *arg_info = 0;
   addr_space_t as1, as2, address_space;
   location_t loc = UNKNOWN_LOCATION;
@@ -5389,9 +5391,9 @@  grokdeclarator (const struct c_declarator *declara
 	case cdk_function:
 	case cdk_pointer:
 	  funcdef_syntax = (decl->kind == cdk_function);
-	  decl = decl->declarator;
 	  if (first_non_attr_kind == cdk_attrs)
 	    first_non_attr_kind = decl->kind;
+	  decl = decl->declarator;
 	  break;
 
 	case cdk_attrs:
@@ -5513,12 +5515,17 @@  grokdeclarator (const struct c_declarator *declara
   if ((TREE_CODE (type) == ARRAY_TYPE
        || first_non_attr_kind == cdk_array)
       && TYPE_QUALS (element_type))
-    type = TYPE_MAIN_VARIANT (type);
+    {
+      orig_qual_type = type;
+      type = TYPE_MAIN_VARIANT (type);
+    }
   type_quals = ((constp ? TYPE_QUAL_CONST : 0)
 		| (restrictp ? TYPE_QUAL_RESTRICT : 0)
 		| (volatilep ? TYPE_QUAL_VOLATILE : 0)
 		| (atomicp ? TYPE_QUAL_ATOMIC : 0)
 		| ENCODE_QUAL_ADDR_SPACE (address_space));
+  if (type_quals != TYPE_QUALS (element_type))
+    orig_qual_type = NULL_TREE;
 
   /* Applying the _Atomic qualifier to an array type (through the use
      of typedefs or typeof) must be detected here.  If the qualifier
@@ -6013,6 +6020,7 @@  grokdeclarator (const struct c_declarator *declara
 		array_ptr_attrs = NULL_TREE;
 		array_parm_static = 0;
 	      }
+	    orig_qual_indirect++;
 	    break;
 	  }
 	case cdk_function:
@@ -6022,6 +6030,7 @@  grokdeclarator (const struct c_declarator *declara
 	       attributes.  */
 	    bool really_funcdef = false;
 	    tree arg_types;
+	    orig_qual_type = NULL_TREE;
 	    if (funcdef_flag)
 	      {
 		const struct c_declarator *t = declarator->declarator;
@@ -6122,7 +6131,9 @@  grokdeclarator (const struct c_declarator *declara
 	      pedwarn (loc, OPT_Wpedantic,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
-	      type = c_build_qualified_type (type, type_quals);
+	      type = c_build_qualified_type (type, type_quals, orig_qual_type,
+					     orig_qual_indirect);
+	    orig_qual_type = NULL_TREE;
 	    size_varies = false;
 
 	    /* When the pointed-to type involves components of variable size,
@@ -6304,7 +6315,8 @@  grokdeclarator (const struct c_declarator *declara
 	pedwarn (loc, OPT_Wpedantic,
 		 "ISO C forbids qualified function types");
       if (type_quals)
-	type = c_build_qualified_type (type, type_quals);
+	type = c_build_qualified_type (type, type_quals, orig_qual_type,
+				       orig_qual_indirect);
       decl = build_decl (declarator->id_loc,
 			 TYPE_DECL, declarator->u.id, type);
       if (declspecs->explicit_signed_p)
@@ -6357,7 +6369,8 @@  grokdeclarator (const struct c_declarator *declara
 	pedwarn (loc, OPT_Wpedantic,
 		 "ISO C forbids const or volatile function types");
       if (type_quals)
-	type = c_build_qualified_type (type, type_quals);
+	type = c_build_qualified_type (type, type_quals, orig_qual_type,
+				       orig_qual_indirect);
       return type;
     }
 
@@ -6405,7 +6418,8 @@  grokdeclarator (const struct c_declarator *declara
 	    /* Transfer const-ness of array into that of type pointed to.  */
 	    type = TREE_TYPE (type);
 	    if (type_quals)
-	      type = c_build_qualified_type (type, type_quals);
+	      type = c_build_qualified_type (type, type_quals, orig_qual_type,
+					     orig_qual_indirect);
 	    type = c_build_pointer_type (type);
 	    type_quals = array_ptr_quals;
 	    if (type_quals)
@@ -6496,7 +6510,8 @@  grokdeclarator (const struct c_declarator *declara
 	    TYPE_DOMAIN (type) = build_range_type (sizetype, size_zero_node,
 						   NULL_TREE);
 	  }
-	type = c_build_qualified_type (type, type_quals);
+	type = c_build_qualified_type (type, type_quals, orig_qual_type,
+				       orig_qual_indirect);
 	decl = build_decl (declarator->id_loc,
 			   FIELD_DECL, declarator->u.id, type);
 	DECL_NONADDRESSABLE_P (decl) = bitfield;
@@ -6608,7 +6623,8 @@  grokdeclarator (const struct c_declarator *declara
 	/* An uninitialized decl with `extern' is a reference.  */
 	int extern_ref = !initialized && storage_class == csc_extern;
 
-	type = c_build_qualified_type (type, type_quals);
+	type = c_build_qualified_type (type, type_quals, orig_qual_type,
+				       orig_qual_indirect);
 
 	/* C99 6.2.2p7: It is invalid (compile-time undefined
 	   behavior) to create an 'extern' declaration for a
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 231075)
+++ gcc/c/c-typeck.c	(working copy)
@@ -13317,10 +13317,15 @@  c_finish_transaction (location_t loc, tree block,
 }
 
 /* Make a variant type in the proper way for C/C++, propagating qualifiers
-   down to the element type of an array.  */
+   down to the element type of an array.  If ORIG_QUAL_TYPE is not
+   NULL, then it should be used as the qualified type
+   ORIG_QUAL_INDIRECT levels down in array type derivation (to
+   preserve information about the typedef name from which an array
+   type was derived).  */
 
 tree
-c_build_qualified_type (tree type, int type_quals)
+c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
+			size_t orig_qual_indirect)
 {
   if (type == error_mark_node)
     return type;
@@ -13329,18 +13334,22 @@  tree
     {
       tree t;
       tree element_type = c_build_qualified_type (TREE_TYPE (type),
-						  type_quals);
+						  type_quals, orig_qual_type,
+						  orig_qual_indirect - 1);
 
       /* See if we already have an identically qualified type.  */
-      for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	{
-	  if (TYPE_QUALS (strip_array_types (t)) == type_quals
-	      && TYPE_NAME (t) == TYPE_NAME (type)
-	      && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
-	      && attribute_list_equal (TYPE_ATTRIBUTES (t),
-				       TYPE_ATTRIBUTES (type)))
-	    break;
-	}
+      if (orig_qual_type && orig_qual_indirect == 0)
+	t = orig_qual_type;
+      else
+	for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+	  {
+	    if (TYPE_QUALS (strip_array_types (t)) == type_quals
+		&& TYPE_NAME (t) == TYPE_NAME (type)
+		&& TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+		&& attribute_list_equal (TYPE_ATTRIBUTES (t),
+					 TYPE_ATTRIBUTES (type)))
+	      break;
+	  }
       if (!t)
 	{
           tree domain = TYPE_DOMAIN (type);
@@ -13384,7 +13393,9 @@  tree
       type_quals &= ~TYPE_QUAL_RESTRICT;
     }
 
-  tree var_type = build_qualified_type (type, type_quals);
+  tree var_type = (orig_qual_type && orig_qual_indirect == 0
+		   ? orig_qual_type
+		   : build_qualified_type (type, type_quals));
   /* A variant type does not inherit the list of incomplete vars from the
      type main variant.  */
   if (RECORD_OR_UNION_TYPE_P (var_type))
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 231075)
+++ gcc/c-family/c-common.h	(working copy)
@@ -866,7 +866,7 @@  extern tree pointer_int_sum (location_t, enum tree
 			     bool = true);
 
 /* Add qualifiers to a type, in the fashion for C.  */
-extern tree c_build_qualified_type (tree, int);
+extern tree c_build_qualified_type (tree, int, tree = NULL_TREE, size_t = 0);
 
 /* Build tree nodes and builtin functions common to both C and C++ language
    frontends.  */
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(revision 231075)
+++ gcc/cp/tree.c	(working copy)
@@ -995,7 +995,8 @@  move (tree expr)
    the C version of this function does not properly maintain canonical
    types (which are not used in C).  */
 tree
-c_build_qualified_type (tree type, int type_quals)
+c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */,
+			size_t /* orig_qual_indirect */)
 {
   return cp_build_qualified_type (type, type_quals);
 }
Index: gcc/testsuite/gcc.dg/pr68162-1.c
===================================================================
--- gcc/testsuite/gcc.dg/pr68162-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr68162-1.c	(revision 0)
@@ -0,0 +1,6 @@ 
+/* Test handling of pointers to arrays of const elements involving a
+   typedef.  PR c/68162.  */
+
+typedef const double cd;
+void f (const double (*)[]);
+void g (void) { f ((cd (*)[]) 0); }