OSDN Git Service

PR c++/13971
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 16 Feb 2004 02:35:50 +0000 (02:35 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 16 Feb 2004 02:35:50 +0000 (02:35 +0000)
* call.c (build_conditional_expr): Handle conversions between
class types which result in differently cv-qualified type
variants.

PR c++/14086
* class.c (delete_duplicate_fields_1): Remove.
(delete_duplicate_fields): Likewise.
(finish_struct_anon): Remove check for members with the same name
as their enclosing class.
(check_field_decls): Do not call duplicate_fields.
* decl.c (grokdeclarator): Remove check for static data members
with the same name as their enclosing class.
* name-lookup.c (push_class_level_binding): Check for members with
the same name as their enclosing class.

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

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/expr/cond4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/crash2.C [new file with mode: 0644]

index 60a0354..6c5e957 100644 (file)
@@ -1,3 +1,21 @@
+2004-02-15  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/13971
+       * call.c (build_conditional_expr): Handle conversions between
+       class types which result in differently cv-qualified type
+       variants.
+
+       PR c++/14086
+       * class.c (delete_duplicate_fields_1): Remove.
+       (delete_duplicate_fields): Likewise.
+       (finish_struct_anon): Remove check for members with the same name
+       as their enclosing class.
+       (check_field_decls): Do not call duplicate_fields.
+       * decl.c (grokdeclarator): Remove check for static data members
+       with the same name as their enclosing class.
+       * name-lookup.c (push_class_level_binding): Check for members with
+       the same name as their enclosing class.
+
 2004-02-15  Gabriel Dos Reis  <gdr@integrable-solutions.net>
 
        PR c++/14085
index ba3b228..70783dc 100644 (file)
@@ -3243,21 +3243,12 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
        {
          arg2 = convert_like (conv2, arg2);
          arg2 = convert_from_reference (arg2);
-         if (!same_type_p (TREE_TYPE (arg2), arg3_type)
-             && CLASS_TYPE_P (arg3_type))
-           /* The types need to match if we're converting to a class type.
-              If not, we don't care about cv-qual mismatches, since
-              non-class rvalues are not cv-qualified.  */
-           abort ();
          arg2_type = TREE_TYPE (arg2);
        }
       else if (conv3 && !conv3->bad_p)
        {
          arg3 = convert_like (conv3, arg3);
          arg3 = convert_from_reference (arg3);
-         if (!same_type_p (TREE_TYPE (arg3), arg2_type)
-             && CLASS_TYPE_P (arg2_type))
-           abort ();
          arg3_type = TREE_TYPE (arg3);
        }
 
@@ -3266,6 +3257,29 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
 
       if (result)
        return result;
+
+      /* If, after the conversion, both operands have class type,
+        treat the cv-qualification of both operands as if it were the
+        union of the cv-qualification of the operands.  
+
+        The standard is not clear about what to do in this
+        circumstance.  For example, if the first operand has type
+        "const X" and the second operand has a user-defined
+        conversion to "volatile X", what is the type of the second
+        operand after this step?  Making it be "const X" (matching
+        the first operand) seems wrong, as that discards the
+        qualification without actuall performing a copy.  Leaving it
+        as "volatile X" seems wrong as that will result in the
+        conditional expression failing altogether, even though,
+        according to this step, the one operand could be converted to
+        the type of the other.  */
+      if ((conv2 || conv3)
+         && CLASS_TYPE_P (arg2_type)
+         && TYPE_QUALS (arg2_type) != TYPE_QUALS (arg3_type))
+       arg2_type = arg3_type = 
+         cp_build_qualified_type (arg2_type,
+                                  TYPE_QUALS (arg2_type)
+                                  | TYPE_QUALS (arg3_type));
     }
 
   /* [expr.cond]
@@ -3349,16 +3363,15 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
      We need to force the lvalue-to-rvalue conversion here for class types,
      so we get TARGET_EXPRs; trying to deal with a COND_EXPR of class rvalues
      that isn't wrapped with a TARGET_EXPR plays havoc with exception
-     regions.
-
-     We use ocp_convert rather than build_user_type_conversion because the
-     latter returns NULL_TREE on failure, while the former gives an error.  */
+     regions.  */
 
   arg2 = force_rvalue (arg2);
-  arg2_type = TREE_TYPE (arg2);
+  if (!CLASS_TYPE_P (arg2_type))
+    arg2_type = TREE_TYPE (arg2);
 
   arg3 = force_rvalue (arg3);
-  arg3_type = TREE_TYPE (arg3);
+  if (!CLASS_TYPE_P (arg2_type))
+    arg3_type = TREE_TYPE (arg3);
 
   if (arg2 == error_mark_node || arg3 == error_mark_node)
     return error_mark_node;
@@ -3445,7 +3458,7 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
   /* Expand both sides into the same slot, hopefully the target of the
      ?: expression.  We used to check for TARGET_EXPRs here, but now we
      sometimes wrap them in NOP_EXPRs so the test would fail.  */
-  if (!lvalue_p && IS_AGGR_TYPE (TREE_TYPE (result)))
+  if (!lvalue_p && CLASS_TYPE_P (TREE_TYPE (result)))
     result = get_target_expr (result);
   
   /* If this expression is an rvalue, but might be mistaken for an
index 96e48e4..f09368f 100644 (file)
@@ -114,8 +114,6 @@ static int build_primary_vtable (tree, tree);
 static int build_secondary_vtable (tree);
 static void finish_vtbls (tree);
 static void modify_vtable_entry (tree, tree, tree, tree, tree *);
-static tree delete_duplicate_fields_1 (tree, tree);
-static void delete_duplicate_fields (tree);
 static void finish_struct_bits (tree);
 static int alter_access (tree, tree, tree);
 static void handle_using_decl (tree, tree);
@@ -957,106 +955,6 @@ add_method (tree type, tree method, int error_p)
 
 /* Subroutines of finish_struct.  */
 
-/* Look through the list of fields for this struct, deleting
-   duplicates as we go.  This must be recursive to handle
-   anonymous unions.
-
-   FIELD is the field which may not appear anywhere in FIELDS.
-   FIELD_PTR, if non-null, is the starting point at which
-   chained deletions may take place.
-   The value returned is the first acceptable entry found
-   in FIELDS.
-
-   Note that anonymous fields which are not of UNION_TYPE are
-   not duplicates, they are just anonymous fields.  This happens
-   when we have unnamed bitfields, for example.  */
-
-static tree
-delete_duplicate_fields_1 (tree field, tree fields)
-{
-  tree x;
-  tree prev = 0;
-  if (DECL_NAME (field) == 0)
-    {
-      if (! ANON_AGGR_TYPE_P (TREE_TYPE (field)))
-       return fields;
-
-      for (x = TYPE_FIELDS (TREE_TYPE (field)); x; x = TREE_CHAIN (x))
-       fields = delete_duplicate_fields_1 (x, fields);
-      return fields;
-    }
-  else
-    {
-      for (x = fields; x; prev = x, x = TREE_CHAIN (x))
-       {
-         if (DECL_NAME (x) == 0)
-           {
-             if (! ANON_AGGR_TYPE_P (TREE_TYPE (x)))
-               continue;
-             TYPE_FIELDS (TREE_TYPE (x))
-               = delete_duplicate_fields_1 (field, TYPE_FIELDS (TREE_TYPE (x)));
-             if (TYPE_FIELDS (TREE_TYPE (x)) == 0)
-               {
-                 if (prev == 0)
-                   fields = TREE_CHAIN (fields);
-                 else
-                   TREE_CHAIN (prev) = TREE_CHAIN (x);
-               }
-           }
-         else if (TREE_CODE (field) == USING_DECL)
-           /* A using declaration is allowed to appear more than
-              once.  We'll prune these from the field list later, and
-              handle_using_decl will complain about invalid multiple
-              uses.  */
-           ;
-         else if (DECL_NAME (field) == DECL_NAME (x))
-           {
-             if (TREE_CODE (field) == CONST_DECL
-                 && TREE_CODE (x) == CONST_DECL)
-               cp_error_at ("duplicate enum value `%D'", x);
-             else if (TREE_CODE (field) == CONST_DECL
-                      || TREE_CODE (x) == CONST_DECL)
-               cp_error_at ("duplicate field `%D' (as enum and non-enum)",
-                            x);
-             else if (DECL_DECLARES_TYPE_P (field)
-                      && DECL_DECLARES_TYPE_P (x))
-               {
-                 if (same_type_p (TREE_TYPE (field), TREE_TYPE (x)))
-                   continue;
-                 cp_error_at ("duplicate nested type `%D'", x);
-               }
-             else if (DECL_DECLARES_TYPE_P (field)
-                      || DECL_DECLARES_TYPE_P (x))
-               {
-                 /* Hide tag decls.  */
-                 if ((TREE_CODE (field) == TYPE_DECL
-                      && DECL_ARTIFICIAL (field))
-                     || (TREE_CODE (x) == TYPE_DECL
-                         && DECL_ARTIFICIAL (x)))
-                   continue;
-                 cp_error_at ("duplicate field `%D' (as type and non-type)",
-                              x);
-               }
-             else
-               cp_error_at ("duplicate member `%D'", x);
-             if (prev == 0)
-               fields = TREE_CHAIN (fields);
-             else
-               TREE_CHAIN (prev) = TREE_CHAIN (x);
-           }
-       }
-    }
-  return fields;
-}
-
-static void
-delete_duplicate_fields (tree fields)
-{
-  tree x;
-  for (x = fields; x && TREE_CHAIN (x); x = TREE_CHAIN (x))
-    TREE_CHAIN (x) = delete_duplicate_fields_1 (x, TREE_CHAIN (x));
-}
-
 /* Change the access of FDECL to ACCESS in T.  Return 1 if change was
    legit, otherwise return 0.  */
 
@@ -2580,10 +2478,6 @@ finish_struct_anon (tree t)
                      || TYPE_ANONYMOUS_P (TREE_TYPE (elt))))
                continue;
 
-             if (constructor_name_p (DECL_NAME (elt), t))
-               cp_pedwarn_at ("ISO C++ forbids member `%D' with same name as enclosing class",
-                              elt);
-
              if (TREE_CODE (elt) != FIELD_DECL)
                {
                  cp_pedwarn_at ("`%#D' invalid; an anonymous union can only have non-static data members",
@@ -2960,9 +2854,6 @@ check_field_decls (tree t, tree *access_decls,
   int has_pointers;
   int any_default_members;
 
-  /* First, delete any duplicate fields.  */
-  delete_duplicate_fields (TYPE_FIELDS (t));
-
   /* Assume there are no access declarations.  */
   *access_decls = NULL_TREE;
   /* Assume this class has no pointer members.  */
index bb6ef73..c071429 100644 (file)
@@ -8274,13 +8274,6 @@ grokdeclarator (tree declarator,
 
            if (staticp)
              {
-               /* [class.mem] forbids static data members with the
-                  same name as the enclosing class.  Non-static data
-                  members are checked in check_field_decls.  */
-               if (constructor_name_p (declarator, current_class_type))
-                 pedwarn ("ISO C++ forbids static data member `%D' with same name as enclosing class",
-                          declarator);
-                 
                /* C++ allows static class members.  All other work
                   for this is done by grokfield.  */
                decl = build_lang_decl (VAR_DECL, declarator, type);
index 1d03dc2..e1cc770 100644 (file)
@@ -2736,6 +2736,37 @@ push_class_level_binding (tree name, tree x)
   if (TYPE_BEING_DEFINED (current_class_type))
     check_template_shadow (x);
 
+  /* [class.mem]
+
+     If T is the name of a class, then each of the following shall
+     have a name different from T:
+
+     -- every static data member of class T;
+
+     -- every member of class T that is itself a type;
+
+     -- every enumerator of every member of class T that is an
+       enumerated type;
+
+     -- every member of every anonymous union that is a member of
+       class T.
+
+     (Non-static data members were also forbidden to have the same
+     name as T until TC1.)  */
+  if ((TREE_CODE (x) == VAR_DECL
+       || TREE_CODE (x) == CONST_DECL
+       || (TREE_CODE (x) == TYPE_DECL
+          && !DECL_SELF_REFERENCE_P (x))
+       /* A data member of an anonymous union.  */
+       || (TREE_CODE (x) == FIELD_DECL
+          && DECL_CONTEXT (x) != current_class_type))
+      && DECL_NAME (x) == constructor_name (current_class_type))
+    {
+      error ("`%D' has the same name as the class in which it is declared",
+            x);
+      POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, false);
+    }
+
   /* If this declaration shadows a declaration from an enclosing
      class, then we will need to restore IDENTIFIER_CLASS_VALUE when
      we leave this class.  Record the shadowed declaration here.  */
index 9148423..49cec6a 100644 (file)
@@ -1,3 +1,11 @@
+2004-02-15  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/13971
+       * g++.dg/expr/cond4.C: New test.
+
+       PR c++/14086
+       * g++.dg/lookup/crash2.C: New test.
+
 2004-02-14  Josef Zlomek  <zlomekj@suse.cz>
 
        * gcc.c-torture/compile/20040214-2.c: New test.
diff --git a/gcc/testsuite/g++.dg/expr/cond4.C b/gcc/testsuite/g++.dg/expr/cond4.C
new file mode 100644 (file)
index 0000000..fff5c8b
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/13971
+
+struct QChar {
+    static const QChar null;
+};
+struct QCharRef {
+    operator QChar() const;
+};
+struct QString {
+    QCharRef operator[](int i);
+};
+
+QChar fillParagraph(QString s, int psi) {
+    return psi ? QChar::null : s[psi];
+}
+
diff --git a/gcc/testsuite/g++.dg/lookup/crash2.C b/gcc/testsuite/g++.dg/lookup/crash2.C
new file mode 100644 (file)
index 0000000..8273524
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/14086
+
+struct ClassA
+{
+  ClassA();
+};
+
+struct ClassB
+{
+  enum Enum {ClassB}; // { dg-error "" }
+  ClassA key;
+
+           ClassB();
+  virtual ~ClassB();
+};
+
+
+ClassB::ClassB()
+{
+}