+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
{
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);
}
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]
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;
/* 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
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);
/* 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. */
|| 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",
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. */
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);
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. */
+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.
--- /dev/null
+// 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];
+}
+
--- /dev/null
+// PR c++/14086
+
+struct ClassA
+{
+ ClassA();
+};
+
+struct ClassB
+{
+ enum Enum {ClassB}; // { dg-error "" }
+ ClassA key;
+
+ ClassB();
+ virtual ~ClassB();
+};
+
+
+ClassB::ClassB()
+{
+}