OSDN Git Service

* c-common.c (fix_string_type): Just use c_build_qualified_type to
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 29 Jan 2005 16:12:45 +0000 (16:12 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 29 Jan 2005 16:12:45 +0000 (16:12 +0000)
build string type.
(c_build_qualified_type): Build qualified array types with
TYPE_MAIN_VARIANT pointing to corresponding unqualified type.
* c-decl.c (c_make_fname_decl): Build unqualified array type
before qualified type.
(grokdeclarator): Use TYPE_MAIN_VARIANT of typedef type if element
type is qualified, not just if type itself is.  Don't apply
qualifiers to array type when declarator is processed.  Apply
qualifiers to field type whether or not it is an array type.
Don't handle array types specially for applying qualifiers to
variables.
* c-typeck.c (composite_type): Build unqualified element type and
array type when forming composite of array types.
(common_pointer_type, comptypes, comp_target_types,
type_lists_compatible_p, build_indirect_ref, build_array_ref,
convert_for_assignment): Don't apply TYPE_MAIN_VARIANT to array
types.
(type_lists_compatible_p): Cache TREE_VALUE (args1) and TREE_VALUE
(args2) in variables a1 and a2.

testsuite:
* gcc.dg/Wwrite-strings-1.c, gcc.dg/array-quals-2.c,
gcc.dg/lvalue-3.c: New tests.
* gcc.dg/concat.c: Update expected messages.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@94411 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wwrite-strings-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/array-quals-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/concat.c
gcc/testsuite/gcc.dg/lvalue-3.c [new file with mode: 0644]

index d0f51a0..3edb615 100644 (file)
@@ -1,3 +1,26 @@
+2005-01-29  Joseph S. Myers  <joseph@codesourcery.com>
+
+       * c-common.c (fix_string_type): Just use c_build_qualified_type to
+       build string type.
+       (c_build_qualified_type): Build qualified array types with
+       TYPE_MAIN_VARIANT pointing to corresponding unqualified type.
+       * c-decl.c (c_make_fname_decl): Build unqualified array type
+       before qualified type.
+       (grokdeclarator): Use TYPE_MAIN_VARIANT of typedef type if element
+       type is qualified, not just if type itself is.  Don't apply
+       qualifiers to array type when declarator is processed.  Apply
+       qualifiers to field type whether or not it is an array type.
+       Don't handle array types specially for applying qualifiers to
+       variables.
+       * c-typeck.c (composite_type): Build unqualified element type and
+       array type when forming composite of array types.
+       (common_pointer_type, comptypes, comp_target_types,
+       type_lists_compatible_p, build_indirect_ref, build_array_ref,
+       convert_for_assignment): Don't apply TYPE_MAIN_VARIANT to array
+       types.
+       (type_lists_compatible_p): Cache TREE_VALUE (args1) and TREE_VALUE
+       (args2) in variables a1 and a2.
+
 2005-01-29  Kazu Hirata  <kazu@cs.umass.edu>
 
        * cse.c (n_elements_made, max_elements_made): Remove.
index 1df71ad..72fd846 100644 (file)
@@ -862,12 +862,7 @@ fix_string_type (tree value)
   i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1));
   a_type = build_array_type (e_type, i_type);
   if (flag_const_strings)
-    {
-      /* bleah, c_build_qualified_type should set TYPE_MAIN_VARIANT.  */
-      tree qa_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST);
-      TYPE_MAIN_VARIANT (qa_type) = a_type;
-      a_type = qa_type;
-    }
+    a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST);
 
   TREE_TYPE (value) = a_type;
   TREE_CONSTANT (value) = 1;
@@ -2483,9 +2478,28 @@ c_build_qualified_type (tree type, int type_quals)
     return type;
 
   if (TREE_CODE (type) == ARRAY_TYPE)
-    return build_array_type (c_build_qualified_type (TREE_TYPE (type),
-                                                    type_quals),
-                            TYPE_DOMAIN (type));
+    {
+      tree t;
+      tree element_type = c_build_qualified_type (TREE_TYPE (type),
+                                                 type_quals);
+
+      /* 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 (!t)
+       {
+         t = build_variant_type_copy (type);
+         TREE_TYPE (t) = element_type;
+       }
+      return t;
+    }
 
   /* A restrict-qualified pointer type must be a pointer to object or
      incomplete type.  Note that the use of POINTER_TYPE_P also allows
index 6e8c742..efb17e8 100644 (file)
@@ -2632,9 +2632,9 @@ c_make_fname_decl (tree id, int type_dep)
   tree decl, type, init;
   size_t length = strlen (name);
 
-  type =  build_array_type
-          (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
-          build_index_type (size_int (length)));
+  type = build_array_type (char_type_node,
+                          build_index_type (size_int (length)));
+  type = c_build_qualified_type (type, TYPE_QUAL_CONST);
 
   decl = build_decl (VAR_DECL, id, type);
 
@@ -3861,7 +3861,7 @@ grokdeclarator (const struct c_declarator *declarator,
       if (volatilep > 1)
        pedwarn ("duplicate %<volatile%>");
     }
-  if (!flag_gen_aux_info && (TYPE_QUALS (type)))
+  if (!flag_gen_aux_info && (TYPE_QUALS (element_type)))
     type = TYPE_MAIN_VARIANT (type);
   type_quals = ((constp ? TYPE_QUAL_CONST : 0)
                | (restrictp ? TYPE_QUAL_RESTRICT : 0)
@@ -3946,7 +3946,13 @@ grokdeclarator (const struct c_declarator *declarator,
 
   /* Now figure out the structure of the declarator proper.
      Descend through it, creating more complex types, until we reach
-     the declared identifier (or NULL_TREE, in an absolute declarator).  */
+     the declared identifier (or NULL_TREE, in an absolute declarator).
+     At each stage we maintain an unqualified version of the type
+     together with any qualifiers that should be applied to it with
+     c_build_qualified_type; this way, array types including
+     multidimensional array types are first built up in unqualified
+     form and then the qualified form is created with
+     TYPE_MAIN_VARIANT pointing to the unqualified form.  */
 
   while (declarator && declarator->kind != cdk_id)
     {
@@ -4146,13 +4152,7 @@ grokdeclarator (const struct c_declarator *declarator,
            if (pedantic && !COMPLETE_TYPE_P (type))
              pedwarn ("array type has incomplete element type");
 
-           /* Build the array type itself, then merge any constancy
-              or volatility into the target type.  We must do it in
-              this order to ensure that the TYPE_MAIN_VARIANT field
-              of the array type is set correctly.  */
            type = build_array_type (type, itype);
-           if (type_quals)
-             type = c_build_qualified_type (type, type_quals);
 
            if (size_varies)
              C_TYPE_VARIABLE_SIZE (type) = 1;
@@ -4278,7 +4278,8 @@ grokdeclarator (const struct c_declarator *declarator,
        }
     }
 
-  /* Now TYPE has the actual type.  */
+  /* Now TYPE has the actual type, apart from any qualifiers in
+     TYPE_QUALS.  */
 
   /* Check the type and width of a bit-field.  */
   if (bitfield)
@@ -4447,11 +4448,7 @@ grokdeclarator (const struct c_declarator *declarator,
            error ("field %qs has incomplete type", name);
            type = error_mark_node;
          }
-       /* Move type qualifiers down to element of an array.  */
-       if (TREE_CODE (type) == ARRAY_TYPE && type_quals)
-         type = build_array_type (c_build_qualified_type (TREE_TYPE (type),
-                                                          type_quals),
-                                  TYPE_DOMAIN (type));
+       type = c_build_qualified_type (type, type_quals);
        decl = build_decl (FIELD_DECL, declarator->u.id, type);
        DECL_NONADDRESSABLE_P (decl) = bitfield;
 
@@ -4556,17 +4553,7 @@ grokdeclarator (const struct c_declarator *declarator,
        /* An uninitialized decl with `extern' is a reference.  */
        int extern_ref = !initialized && storage_class == csc_extern;
 
-       /* Move type qualifiers down to element of an array.  */
-       if (TREE_CODE (type) == ARRAY_TYPE && type_quals)
-         {
-           int saved_align = TYPE_ALIGN(type);
-           type = build_array_type (c_build_qualified_type (TREE_TYPE (type),
-                                                            type_quals),
-                                    TYPE_DOMAIN (type));
-           TYPE_ALIGN (type) = saved_align;
-         }
-       else if (type_quals)
-         type = c_build_qualified_type (type, type_quals);
+       type = c_build_qualified_type (type, type_quals);
 
        /* C99 6.2.2p7: It is invalid (compile-time undefined
           behavior) to create an 'extern' declaration for a
index cb657df..fed17f2 100644 (file)
@@ -277,7 +277,9 @@ composite_type (tree t1, tree t2)
     case ARRAY_TYPE:
       {
        tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
-       
+       int quals;
+       tree unqual_elt;
+
        /* We should not have any type quals on arrays at all.  */
        gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
        
@@ -292,8 +294,16 @@ composite_type (tree t1, tree t2)
        if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
          return build_type_attribute_variant (t2, attributes);
        
-       /* Merge the element types, and have a size if either arg has one.  */
-       t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+       /* Merge the element types, and have a size if either arg has
+          one.  We may have qualifiers on the element types.  To set
+          up TYPE_MAIN_VARIANT correctly, we need to form the
+          composite of the unqualified types and add the qualifiers
+          back at the end.  */
+       quals = TYPE_QUALS (strip_array_types (elt));
+       unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+       t1 = build_array_type (unqual_elt,
+                              TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+       t1 = c_build_qualified_type (t1, quals);
        return build_type_attribute_variant (t1, attributes);
       }
 
@@ -415,8 +425,8 @@ static tree
 common_pointer_type (tree t1, tree t2)
 {
   tree attributes;
-  tree pointed_to_1;
-  tree pointed_to_2;
+  tree pointed_to_1, mv1;
+  tree pointed_to_2, mv2;
   tree target;
 
   /* Save time if the two types are the same.  */
@@ -436,11 +446,15 @@ common_pointer_type (tree t1, tree t2)
   attributes = targetm.merge_type_attributes (t1, t2);
 
   /* Find the composite type of the target types, and combine the
-     qualifiers of the two types' targets.  */
-  pointed_to_1 = TREE_TYPE (t1);
-  pointed_to_2 = TREE_TYPE (t2);
-  target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1),
-                          TYPE_MAIN_VARIANT (pointed_to_2));
+     qualifiers of the two types' targets.  Do not lose qualifiers on
+     array element types by taking the TYPE_MAIN_VARIANT.  */
+  mv1 = pointed_to_1 = TREE_TYPE (t1);
+  mv2 = pointed_to_2 = TREE_TYPE (t2);
+  if (TREE_CODE (mv1) != ARRAY_TYPE)
+    mv1 = TYPE_MAIN_VARIANT (pointed_to_1);
+  if (TREE_CODE (mv2) != ARRAY_TYPE)
+    mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
+  target = composite_type (mv1, mv2);
   t1 = build_pointer_type (c_build_qualified_type
                           (target,
                            TYPE_QUALS (pointed_to_1) |
@@ -632,7 +646,8 @@ comptypes (tree type1, tree type2)
      definition.  Note that we already checked for equality of the type
      qualifiers (just above).  */
 
-  if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+  if (TREE_CODE (t1) != ARRAY_TYPE
+      && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return 1;
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -734,13 +749,21 @@ static int
 comp_target_types (tree ttl, tree ttr, int reflexive)
 {
   int val;
+  tree mvl, mvr;
 
   /* Give objc_comptypes a crack at letting these types through.  */
   if ((val = objc_comptypes (ttl, ttr, reflexive)) >= 0)
     return val;
 
-  val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
-                  TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+  /* Do not lose qualifiers on element types of array types that are
+     pointer targets by taking their TYPE_MAIN_VARIANT.  */
+  mvl = TREE_TYPE (ttl);
+  mvr = TREE_TYPE (ttr);
+  if (TREE_CODE (mvl) != ARRAY_TYPE)
+    mvl = TYPE_MAIN_VARIANT (mvl);
+  if (TREE_CODE (mvr) != ARRAY_TYPE)
+    mvr = TYPE_MAIN_VARIANT (mvr);
+  val = comptypes (mvl, mvr);
 
   if (val == 2 && pedantic)
     pedwarn ("types are not quite compatible");
@@ -1042,61 +1065,67 @@ type_lists_compatible_p (tree args1, tree args2)
 
   while (1)
     {
+      tree a1, mv1, a2, mv2;
       if (args1 == 0 && args2 == 0)
        return val;
       /* If one list is shorter than the other,
         they fail to match.  */
       if (args1 == 0 || args2 == 0)
        return 0;
+      mv1 = a1 = TREE_VALUE (args1);
+      mv2 = a2 = TREE_VALUE (args2);
+      if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
+       mv1 = TYPE_MAIN_VARIANT (mv1);
+      if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
+       mv2 = TYPE_MAIN_VARIANT (mv2);
       /* A null pointer instead of a type
         means there is supposed to be an argument
         but nothing is specified about what type it has.
         So match anything that self-promotes.  */
-      if (TREE_VALUE (args1) == 0)
+      if (a1 == 0)
        {
-         if (c_type_promotes_to (TREE_VALUE (args2)) != TREE_VALUE (args2))
+         if (c_type_promotes_to (a2) != a2)
            return 0;
        }
-      else if (TREE_VALUE (args2) == 0)
+      else if (a2 == 0)
        {
-         if (c_type_promotes_to (TREE_VALUE (args1)) != TREE_VALUE (args1))
+         if (c_type_promotes_to (a1) != a1)
            return 0;
        }
       /* If one of the lists has an error marker, ignore this arg.  */
-      else if (TREE_CODE (TREE_VALUE (args1)) == ERROR_MARK
-              || TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
+      else if (TREE_CODE (a1) == ERROR_MARK
+              || TREE_CODE (a2) == ERROR_MARK)
        ;
-      else if (!(newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
-                                    TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+      else if (!(newval = comptypes (mv1, mv2)))
        {
          /* Allow  wait (union {union wait *u; int *i} *)
             and  wait (union wait *)  to be compatible.  */
-         if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE
-             && (TYPE_NAME (TREE_VALUE (args1)) == 0
-                 || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1)))
-             && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST
-             && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)),
-                                    TYPE_SIZE (TREE_VALUE (args2))))
+         if (TREE_CODE (a1) == UNION_TYPE
+             && (TYPE_NAME (a1) == 0
+                 || TYPE_TRANSPARENT_UNION (a1))
+             && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
+             && tree_int_cst_equal (TYPE_SIZE (a1),
+                                    TYPE_SIZE (a2)))
            {
              tree memb;
-             for (memb = TYPE_FIELDS (TREE_VALUE (args1));
+             for (memb = TYPE_FIELDS (a1);
                   memb; memb = TREE_CHAIN (memb))
-               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
+               if (comptypes (TREE_TYPE (memb), a2))
                  break;
              if (memb == 0)
                return 0;
            }
-         else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
-                  && (TYPE_NAME (TREE_VALUE (args2)) == 0
-                      || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2)))
-                  && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST
-                  && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)),
-                                         TYPE_SIZE (TREE_VALUE (args1))))
+         else if (TREE_CODE (a2) == UNION_TYPE
+                  && (TYPE_NAME (a2) == 0
+                      || TYPE_TRANSPARENT_UNION (a2))
+                  && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
+                  && tree_int_cst_equal (TYPE_SIZE (a2),
+                                         TYPE_SIZE (a1)))
            {
              tree memb;
-             for (memb = TYPE_FIELDS (TREE_VALUE (args2));
+             for (memb = TYPE_FIELDS (a2);
                   memb; memb = TREE_CHAIN (memb))
-               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
+               if (comptypes (TREE_TYPE (memb), a1))
                  break;
              if (memb == 0)
                return 0;
@@ -1542,7 +1571,12 @@ build_indirect_ref (tree ptr, const char *errorstring)
       else
        {
          tree t = TREE_TYPE (type);
-         tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
+         tree mvt = t;
+         tree ref;
+
+         if (TREE_CODE (mvt) != ARRAY_TYPE)
+           mvt = TYPE_MAIN_VARIANT (mvt);
+         ref = build1 (INDIRECT_REF, mvt, pointer);
 
          if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
            {
@@ -1670,7 +1704,9 @@ build_array_ref (tree array, tree index)
            pedwarn ("ISO C90 forbids subscripting non-lvalue array");
        }
 
-      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
+      type = TREE_TYPE (TREE_TYPE (array));
+      if (TREE_CODE (type) != ARRAY_TYPE)
+       type = TYPE_MAIN_VARIANT (type);
       rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
       /* Array ref is const/volatile if the array elements are
          or if the array is.  */
@@ -3597,9 +3633,15 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
     {
       tree ttl = TREE_TYPE (type);
       tree ttr = TREE_TYPE (rhstype);
+      tree mvl = ttl;
+      tree mvr = ttr;
       bool is_opaque_pointer;
       int target_cmp = 0;   /* Cache comp_target_types () result.  */
 
+      if (TREE_CODE (mvl) != ARRAY_TYPE)
+       mvl = TYPE_MAIN_VARIANT (mvl);
+      if (TREE_CODE (mvr) != ARRAY_TYPE)
+       mvr = TYPE_MAIN_VARIANT (mvr);
       /* Opaque pointers are treated like void pointers.  */
       is_opaque_pointer = (targetm.vector_opaque_p (type)
                            || targetm.vector_opaque_p (rhstype))
@@ -3612,8 +3654,8 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
       if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
          || (target_cmp = comp_target_types (type, rhstype, 0))
          || is_opaque_pointer
-         || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
-             == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
+         || (c_common_unsigned_type (mvl)
+             == c_common_unsigned_type (mvr)))
        {
          if (pedantic
              && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
index 2fc135f..e7ff37e 100644 (file)
@@ -1,3 +1,9 @@
+2005-01-29  Joseph S. Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/Wwrite-strings-1.c, gcc.dg/array-quals-2.c,
+       gcc.dg/lvalue-3.c: New tests.
+       * gcc.dg/concat.c: Update expected messages.
+
 2005-01-29  Thomas Koenig  <Thomas.Koenig@online.de>
 
        PR libfortran/19595
diff --git a/gcc/testsuite/gcc.dg/Wwrite-strings-1.c b/gcc/testsuite/gcc.dg/Wwrite-strings-1.c
new file mode 100644 (file)
index 0000000..9270e8f
--- /dev/null
@@ -0,0 +1,8 @@
+/* Test pointer initialization and dereference don't lose qualifiers
+   on array types.  This test wrongly failed to diagnose the loss of
+   const.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-Wwrite-strings" } */
+typedef char T[1];
+T *p = &""; /* { dg-warning "warning: initialization from incompatible pointer type" } */
diff --git a/gcc/testsuite/gcc.dg/array-quals-2.c b/gcc/testsuite/gcc.dg/array-quals-2.c
new file mode 100644 (file)
index 0000000..5d20244
--- /dev/null
@@ -0,0 +1,14 @@
+/* Test that pointers to arrays of differently qualified types aren't
+   permitted in conditional expressions, and that qualifiers aren't
+   lost in forming composite types.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+typedef const char T[1];
+typedef const char T2[1];
+typedef volatile char U[1];
+T *p;
+T2 *p2;
+U *q;
+void *f(void) { return 1 ? p : q; } /* { dg-warning "warning: pointer type mismatch in conditional expression" } */
+T *g(void) { return 1 ? p : p2; }
index 9503368..0b9d6f6 100644 (file)
@@ -8,8 +8,8 @@
 
 void foo ()
 {
-  char s1[] = __FUNCTION__".";      /* { dg-error "(parse|syntax|expected|invalid)" } */
-  char s2[] = __PRETTY_FUNCTION__".";/* { dg-error "(parse|syntax|expected|invalid)" } */
+  char s1[] = __FUNCTION__".";      /* { dg-error "(parse|syntax|expected|invalid|array)" } */
+  char s2[] = __PRETTY_FUNCTION__".";/* { dg-error "(parse|syntax|expected|invalid|array)" } */
   char s3[] = "."__FUNCTION__;      /* { dg-error "(parse|syntax|expected|invalid)" } */
   char s4[] = "."__PRETTY_FUNCTION__;/* { dg-error "(parse|syntax|expected|invalid)" } */
   char s5[] = "."".";                /* No error.  */
diff --git a/gcc/testsuite/gcc.dg/lvalue-3.c b/gcc/testsuite/gcc.dg/lvalue-3.c
new file mode 100644 (file)
index 0000000..0745c7e
--- /dev/null
@@ -0,0 +1,14 @@
+/* Test that assignment of a read-only variable that gets const-ness
+   from a read-only field is diagnosed.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct s { const int a; } x;
+typeof (x.a) b;
+void
+f (void)
+{
+  x.a = 1; /* { dg-error "error: assignment of read-only member 'a'" } */
+  b = 1; /* { dg-error "error: assignment of read-only variable 'b'" } */
+}