diff options
Diffstat (limited to 'contrib/gcc/cp/semantics.c')
-rw-r--r-- | contrib/gcc/cp/semantics.c | 461 |
1 files changed, 377 insertions, 84 deletions
diff --git a/contrib/gcc/cp/semantics.c b/contrib/gcc/cp/semantics.c index 5068512..7267f46 100644 --- a/contrib/gcc/cp/semantics.c +++ b/contrib/gcc/cp/semantics.c @@ -3,7 +3,7 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998 Free Software Foundation, Inc. + Copyright (C) 1998, 1999 Free Software Foundation, Inc. Written by Mark Mitchell (mmitchell@usa.net) based on code found formerly in parse.y and pt.c. @@ -120,7 +120,7 @@ finish_if_stmt_cond (cond, if_stmt) if (last_tree != if_stmt) RECHAIN_STMTS_FROM_LAST (if_stmt, IF_COND (if_stmt)); else - IF_COND (if_stmt) = cond; + IF_COND (if_stmt) = copy_to_permanent (cond); } else { @@ -219,7 +219,7 @@ finish_while_stmt_cond (cond, while_stmt) RECHAIN_STMTS_FROM_LAST (while_stmt, WHILE_COND (while_stmt)); else - TREE_OPERAND (while_stmt, 0) = cond; + TREE_OPERAND (while_stmt, 0) = copy_to_permanent (cond); } else { @@ -294,7 +294,7 @@ finish_do_stmt (cond, do_stmt) tree do_stmt; { if (processing_template_decl) - DO_COND (do_stmt) = cond; + DO_COND (do_stmt) = copy_to_permanent (cond); else { emit_line_note (input_filename, lineno); @@ -378,7 +378,7 @@ finish_for_cond (cond, for_stmt) if (last_tree != for_stmt) RECHAIN_STMTS_FROM_LAST (for_stmt, FOR_COND (for_stmt)); else - FOR_COND (for_stmt) = cond; + FOR_COND (for_stmt) = copy_to_permanent (cond); } else { @@ -490,12 +490,20 @@ finish_switch_cond (cond) r = build_min_nt (SWITCH_STMT, cond, NULL_TREE); add_tree (r); } - else + else if (cond != error_mark_node) { emit_line_note (input_filename, lineno); c_expand_start_case (cond); r = NULL_TREE; } + else + { + /* The code is in error, but we don't want expand_end_case to + crash. */ + c_expand_start_case (boolean_false_node); + r = NULL_TREE; + } + push_switch (); /* Don't let the tree nodes for COND be discarded by @@ -731,13 +739,18 @@ finish_asm_stmt (cv_qualifier, string, output_operands, { emit_line_note (input_filename, lineno); if (output_operands != NULL_TREE || input_operands != NULL_TREE - || clobbers != NULL_TREE) + || clobbers != NULL_TREE) { + tree t; + if (cv_qualifier != NULL_TREE && cv_qualifier != ridpointers[(int) RID_VOLATILE]) cp_warning ("%s qualifier ignored on asm", IDENTIFIER_POINTER (cv_qualifier)); - + + for (t = input_operands; t; t = TREE_CHAIN (t)) + TREE_VALUE (t) = decay_conversion (TREE_VALUE (t)); + c_expand_asm_operands (string, output_operands, input_operands, clobbers, @@ -747,12 +760,14 @@ finish_asm_stmt (cv_qualifier, string, output_operands, } else { - if (cv_qualifier != NULL_TREE) + /* Don't warn about redundant specification of 'volatile' here. */ + if (cv_qualifier != NULL_TREE + && cv_qualifier != ridpointers[(int) RID_VOLATILE]) cp_warning ("%s qualifier ignored on asm", IDENTIFIER_POINTER (cv_qualifier)); expand_asm (string); } - + finish_stmt (); } } @@ -807,8 +822,8 @@ finish_stmt_expr (rtl_expr, expr) { /* Make a BIND_EXPR for the BLOCK already made. */ if (processing_template_decl) - result = build (BIND_EXPR, NULL_TREE, - NULL_TREE, last_tree, expr); + result = build_min_nt (BIND_EXPR, NULL_TREE, last_tree, + NULL_TREE); else result = build (BIND_EXPR, TREE_TYPE (rtl_expr), NULL_TREE, rtl_expr, expr); @@ -853,7 +868,8 @@ finish_call_expr (fn, args, koenig) result = build_x_function_call (fn, args, current_class_ref); if (TREE_CODE (result) == CALL_EXPR - && TREE_TYPE (result) != void_type_node) + && (! TREE_TYPE (result) + || TREE_CODE (TREE_TYPE (result)) != VOID_TYPE)) result = require_complete_type (result); return result; @@ -995,7 +1011,7 @@ finish_pseudo_destructor_call_expr (object, scope, destructor) ARGS. Returns an expression for the call. */ tree -finish_globally_qualified_member_call_expr (fn, args) +finish_qualified_call_expr (fn, args) tree fn; tree args; { @@ -1098,6 +1114,10 @@ begin_function_definition (decl_specs, declarator) return 0; reinit_parse_for_function (); + /* The things we're about to see are not directly qualified by any + template headers we've seen thus far. */ + reset_specialization (); + return 1; } @@ -1110,13 +1130,7 @@ begin_constructor_declarator (scope, name) tree name; { tree result = build_parse_node (SCOPE_REF, scope, name); - - if (scope != current_class_type) - { - push_nested_class (scope, 3); - TREE_COMPLEXITY (result) = current_class_depth; - } - + enter_scope_of (result); return result; } @@ -1210,50 +1224,85 @@ tree begin_class_definition (t) tree t; { - tree new_type = t; - push_obstacks_nochange (); end_temporary_allocation (); if (t == error_mark_node || ! IS_AGGR_TYPE (t)) { - t = new_type = make_lang_type (RECORD_TYPE); + t = make_lang_type (RECORD_TYPE); pushtag (make_anon_name (), t, 0); } - if (TYPE_SIZE (t)) + + /* In a definition of a member class template, we will get here with an + implicit typename, a TYPENAME_TYPE with a type. */ + if (TREE_CODE (t) == TYPENAME_TYPE) + t = TREE_TYPE (t); + + /* If we generated a partial instantiation of this type, but now + we're seeing a real definition, we're actually looking at a + partial specialization. Consider: + + template <class T, class U> + struct Y {}; + + template <class T> + struct X {}; + + template <class T, class U> + void f() + { + typename X<Y<T, U> >::A a; + } + + template <class T, class U> + struct X<Y<T, U> > + { + }; + + We have to undo the effects of the previous partial + instantiation. */ + if (PARTIAL_INSTANTIATION_P (t)) + { + if (!pedantic) + { + /* Unfortunately, when we're not in pedantic mode, we + attempt to actually fill in some of the fields of the + partial instantiation, in order to support the implicit + typename extension. Clear those fields now, in + preparation for the definition here. The fields cleared + here must match those set in instantiate_class_template. + Look for a comment mentioning begin_class_definition + there. */ + TYPE_BINFO_BASETYPES (t) = NULL_TREE; + TYPE_FIELDS (t) = NULL_TREE; + TYPE_METHODS (t) = NULL_TREE; + CLASSTYPE_TAGS (t) = NULL_TREE; + TYPE_SIZE (t) = NULL_TREE; + } + + /* This isn't a partial instantiation any more. */ + PARTIAL_INSTANTIATION_P (t) = 0; + } + /* If this type was already complete, and we see another definition, + that's an error. */ + else if (TYPE_SIZE (t)) duplicate_tag_error (t); - if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t)) + + if (TYPE_BEING_DEFINED (t)) { t = make_lang_type (TREE_CODE (t)); pushtag (TYPE_IDENTIFIER (t), t, 0); - new_type = t; } - if (processing_template_decl && TYPE_CONTEXT (t) - && TREE_CODE (TYPE_CONTEXT (t)) != NAMESPACE_DECL - && ! current_class_type) - push_template_decl (TYPE_STUB_DECL (t)); - pushclass (t, 0); + maybe_process_partial_specialization (t); + pushclass (t, 1); TYPE_BEING_DEFINED (t) = 1; - if (IS_AGGR_TYPE (t) && CLASSTYPE_USE_TEMPLATE (t)) - { - if (CLASSTYPE_IMPLICIT_INSTANTIATION (t) - && TYPE_SIZE (t) == NULL_TREE) - { - SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t); - if (processing_template_decl) - push_template_decl (TYPE_MAIN_DECL (t)); - } - else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t)) - cp_error ("specialization after instantiation of `%T'", t); - } /* Reset the interface data, at the earliest possible moment, as it might have been set via a class foo; before. */ /* Don't change signatures. */ if (! IS_SIGNATURE (t)) { - extern tree pending_vtables; int needs_writing; tree name = TYPE_IDENTIFIER (t); @@ -1265,30 +1314,19 @@ begin_class_definition (t) } /* Record how to set the access of this class's - virtual functions. If write_virtuals == 2 or 3, then + virtual functions. If write_virtuals == 3, then inline virtuals are ``extern inline''. */ - switch (write_virtuals) - { - case 0: - case 1: - needs_writing = 1; - break; - case 2: - needs_writing = !! value_member (name, pending_vtables); - break; - case 3: - needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t) - && CLASSTYPE_INTERFACE_KNOWN (t); - break; - default: - needs_writing = 0; - } + if (write_virtuals == 3) + needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t) + && CLASSTYPE_INTERFACE_KNOWN (t); + else + needs_writing = 1; CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing; } #if 0 - t = TYPE_IDENTIFIER ($<ttype>0); - if (t && IDENTIFIER_TEMPLATE (t)) - overload_template_name (t, 1); + tmp = TYPE_IDENTIFIER ($<ttype>0); + if (tmp && IDENTIFIER_TEMPLATE (tmp)) + overload_template_name (tmp, 1); #endif reset_specialization(); @@ -1297,26 +1335,108 @@ begin_class_definition (t) that we can get it back later. */ begin_tree (); - return new_type; + /* Make a declaration for this class in its own scope. */ + build_self_reference (); + + return t; } -/* Finish a class definition T, with the indicated COMPONENTS, and - with the indicate ATTRIBUTES. If SEMI, the definition is - immediately followed by a semicolon. Returns the type. */ +/* Finish the member declaration given by DECL. */ + +void +finish_member_declaration (decl) + tree decl; +{ + if (decl == error_mark_node || decl == NULL_TREE) + return; + + if (decl == void_type_node) + /* The COMPONENT was a friend, not a member, and so there's + nothing for us to do. */ + return; + + /* We should see only one DECL at a time. */ + my_friendly_assert (TREE_CHAIN (decl) == NULL_TREE, 0); + + /* Set up access control for DECL. */ + TREE_PRIVATE (decl) + = (current_access_specifier == access_private_node); + TREE_PROTECTED (decl) + = (current_access_specifier == access_protected_node); + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + TREE_PRIVATE (DECL_RESULT (decl)) = TREE_PRIVATE (decl); + TREE_PROTECTED (DECL_RESULT (decl)) = TREE_PROTECTED (decl); + } + + /* Mark the DECL as a member of the current class. */ + if (TREE_CODE (decl) == FUNCTION_DECL + || DECL_FUNCTION_TEMPLATE_P (decl)) + /* Historically, DECL_CONTEXT was not set for a FUNCTION_DECL in + finish_struct. Presumably it is already set as the function is + parsed. Perhaps DECL_CLASS_CONTEXT is already set, too? */ + DECL_CLASS_CONTEXT (decl) = current_class_type; + else + DECL_CONTEXT (decl) = current_class_type; + + /* Put functions on the TYPE_METHODS list and everything else on the + TYPE_FIELDS list. Note that these are built up in reverse order. + We reverse them (to obtain declaration order) in finish_struct. */ + if (TREE_CODE (decl) == FUNCTION_DECL + || DECL_FUNCTION_TEMPLATE_P (decl)) + { + /* We also need to add this function to the + CLASSTYPE_METHOD_VEC. */ + add_method (current_class_type, 0, decl); + + TREE_CHAIN (decl) = TYPE_METHODS (current_class_type); + TYPE_METHODS (current_class_type) = decl; + } + else + { + /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields + go at the beginning. The reason is that lookup_field_1 + searches the list in order, and we want a field name to + override a type name so that the "struct stat hack" will + work. In particular: + + struct S { enum E { }; int E } s; + s.E = 3; + + is legal. In addition, the FIELD_DECLs must be maintained in + declaration order so that class layout works as expected. + However, we don't need that order until class layout, so we + save a little time by putting FIELD_DECLs on in reverse order + here, and then reversing them in finish_struct_1. (We could + also keep a pointer to the correct insertion points in the + list.) */ + + if (TREE_CODE (decl) == TYPE_DECL) + TYPE_FIELDS (current_class_type) + = chainon (TYPE_FIELDS (current_class_type), decl); + else + { + TREE_CHAIN (decl) = TYPE_FIELDS (current_class_type); + TYPE_FIELDS (current_class_type) = decl; + } + + /* Enter the DECL into the scope of the class. */ + if (TREE_CODE (decl) != USING_DECL) + pushdecl_class_level (decl); + } +} + +/* Finish a class definition T with the indicate ATTRIBUTES. If SEMI, + the definition is immediately followed by a semicolon. Returns the + type. */ tree -finish_class_definition (t, components, attributes, semi) +finish_class_definition (t, attributes, semi, pop_scope_p) tree t; - tree components; tree attributes; int semi; + int pop_scope_p; { -#if 0 - /* Need to rework class nesting in the presence of nested classes, - etc. */ - shadow_tag (CLASSTYPE_AS_LIST (t)); */ -#endif - /* finish_struct nukes this anyway; if finish_exception does too, then it can go. */ if (semi) @@ -1331,7 +1451,7 @@ finish_class_definition (t, components, attributes, semi) ; else { - t = finish_struct (t, components, attributes, semi); + t = finish_struct (t, attributes, semi); if (semi) note_got_semicolon (t); } @@ -1340,6 +1460,8 @@ finish_class_definition (t, components, attributes, semi) if (! semi) check_for_missing_semicolon (t); + if (pop_scope_p) + pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t))); if (current_scope () == current_function_decl) do_pending_defargs (); @@ -1350,7 +1472,7 @@ finish_class_definition (t, components, attributes, semi) the processing of a class definition. */ void -finish_default_args () +begin_inline_definitions () { if (pending_inlines && current_scope () == current_function_decl) @@ -1361,7 +1483,7 @@ finish_default_args () processing of a class definition. */ void -begin_inline_definitions () +finish_inline_definitions () { if (current_class_type == NULL_TREE) clear_inline_text_obstack (); @@ -1374,20 +1496,191 @@ begin_inline_definitions () TYPES whose template parameters are given by PARMS. */ tree -finish_member_class_template (parms, types) - tree parms; +finish_member_class_template (types) tree types; { + tree t; + + /* If there are declared, but undefined, partial specializations + mixed in with the typespecs they will not yet have passed through + maybe_process_partial_specialization, so we do that here. */ + for (t = types; t != NULL_TREE; t = TREE_CHAIN (t)) + if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t)))) + maybe_process_partial_specialization (TREE_VALUE (t)); + note_list_got_semicolon (types); - grok_x_components (types, NULL_TREE); + grok_x_components (types); if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type) /* The component was in fact a friend declaration. We avoid finish_member_template_decl performing certain checks by unsetting TYPES. */ types = NULL_TREE; - finish_member_template_decl (parms, types); + + finish_member_template_decl (types); + /* As with other component type declarations, we do not store the new DECL on the list of component_decls. */ return NULL_TREE; } + +/* Finish processsing a complete template declaration. The PARMS are + the template parameters. */ + +void +finish_template_decl (parms) + tree parms; +{ + if (parms) + end_template_decl (); + else + end_specialization (); +} + +/* Finish processing a a template-id (which names a type) of the form + NAME < ARGS >. Return the TYPE_DECL for the type named by the + template-id. If ENTERING_SCOPE is non-zero we are about to enter + the scope of template-id indicated. */ + +tree +finish_template_type (name, args, entering_scope) + tree name; + tree args; + int entering_scope; +{ + tree decl; + + decl = lookup_template_class (name, args, + NULL_TREE, NULL_TREE, entering_scope); + if (decl != error_mark_node) + decl = TYPE_STUB_DECL (decl); + + return decl; +} + +/* SR is a SCOPE_REF node. Enter the scope of SR, whether it is a + namespace scope or a class scope. */ + +void +enter_scope_of (sr) + tree sr; +{ + tree scope = TREE_OPERAND (sr, 0); + + if (TREE_CODE (scope) == NAMESPACE_DECL) + { + push_decl_namespace (scope); + TREE_COMPLEXITY (sr) = -1; + } + else if (scope != current_class_type) + { + if (TREE_CODE (scope) == TYPENAME_TYPE) + { + /* In a declarator for a template class member, the scope will + get here as an implicit typename, a TYPENAME_TYPE with a type. */ + scope = TREE_TYPE (scope); + TREE_OPERAND (sr, 0) = scope; + } + push_nested_class (scope, 3); + TREE_COMPLEXITY (sr) = current_class_depth; + } +} + +/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER. + Return a TREE_LIST containing the ACCESS_SPECIFIER and the + BASE_CLASS, or NULL_TREE if an error occurred. The + ACCESSS_SPECIFIER is one of + access_{default,public,protected_private}[_virtual]_node.*/ + +tree +finish_base_specifier (access_specifier, base_class, + current_aggr_is_signature) + tree access_specifier; + tree base_class; + int current_aggr_is_signature; +{ + tree type; + tree result; + + if (base_class == NULL_TREE) + { + error ("invalid base class"); + type = error_mark_node; + } + else + type = TREE_TYPE (base_class); + if (current_aggr_is_signature && access_specifier) + error ("access and source specifiers not allowed in signature"); + if (! is_aggr_type (type, 1)) + result = NULL_TREE; + else if (current_aggr_is_signature + && (! type) && (! IS_SIGNATURE (type))) + { + error ("class name not allowed as base signature"); + result = NULL_TREE; + } + else if (current_aggr_is_signature) + { + sorry ("signature inheritance, base type `%s' ignored", + IDENTIFIER_POINTER (access_specifier)); + result = build_tree_list (access_public_node, type); + } + else if (type && IS_SIGNATURE (type)) + { + error ("signature name not allowed as base class"); + result = NULL_TREE; + } + else + result = build_tree_list (access_specifier, type); + + return result; +} + +/* Called when multiple declarators are processed. If that is not + premitted in this context, an error is issued. */ + +void +check_multiple_declarators () +{ + /* [temp] + + In a template-declaration, explicit specialization, or explicit + instantiation the init-declarator-list in the declaration shall + contain at most one declarator. + + We don't just use PROCESSING_TEMPLATE_DECL for the first + condition since that would disallow the perfectly legal code, + like `template <class T> struct S { int i, j; };'. */ + tree scope = current_scope (); + + if (scope && TREE_CODE (scope) == FUNCTION_DECL) + /* It's OK to write `template <class T> void f() { int i, j;}'. */ + return; + + if (PROCESSING_REAL_TEMPLATE_DECL_P () + || processing_explicit_instantiation + || processing_specialization) + cp_error ("multiple declarators in template declaration"); +} + +tree +finish_typeof (expr) + tree expr; +{ + if (processing_template_decl) + { + tree t; + + push_obstacks_nochange (); + end_temporary_allocation (); + + t = make_lang_type (TYPEOF_TYPE); + TYPE_FIELDS (t) = expr; + + pop_obstacks (); + + return t; + } + + return TREE_TYPE (expr); +} |