diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/cp/call.c | 45 | ||||
-rw-r--r-- | gcc/cp/class.c | 109 | ||||
-rw-r--r-- | gcc/cp/decl.c | 7 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 31 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/expr/cond4.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/crash2.C | 20 |
8 files changed, 122 insertions, 132 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 60a0354..6c5e957 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ba3b228..70783dc 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 96e48e4..f09368f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bb6ef73..c071429 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 1d03dc2..e1cc770 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9148423..49cec6a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..fff5c8b --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/cond4.C @@ -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 index 0000000..8273524 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/crash2.C @@ -0,0 +1,20 @@ +// PR c++/14086 + +struct ClassA +{ + ClassA(); +}; + +struct ClassB +{ + enum Enum {ClassB}; // { dg-error "" } + ClassA key; + + ClassB(); + virtual ~ClassB(); +}; + + +ClassB::ClassB() +{ +} |