+1999-08-13 Mark Mitchell <mark@codesourcery.com>
+
+ * cp-tree.def (DECL_STMT): Make it smaller.
+ * cp-tree.h (lang_decl_flags): Move saved_tree to ...
+ (lang_decl): ... here. Add next.
+ (DECL_SAVED_TREE): Adjust accordingly.
+ (DECL_IMPLICIT_TYPEDEF_P): New macro.
+ (SET_DECL_IMPLICIT_TYPEDEF_P): Likewise.
+ (DECL_STMT_DECL): Likewise.
+ (create_implicit_typedef): New function.
+ (maybe_push_decl): Likewise.
+ (tsubst_default_argument): New function.
+ (at_function_scope_p): Likewise.
+ (add_decl_stmt): Likewise.
+ (push_permanent_obstack): Likewise.
+ * call.c (convert_default_arg): Use tsubst_default_argument.
+ * class.c (add_method): Use push_permanent_obstack.
+ (build_self_reference): Create a TEMPLATE_DECL for the
+ self-reference, if necessary.
+ * decl.c (pseudo_global_level_p): Only look at the current binding
+ level.
+ (push_binding): Use push_permanent_obstack.
+ (create_implicit_typedef): New function.
+ (pushtag): Use it.
+ (duplicate_decls): Use push_permanent_obstack.
+ (maybe_push_decl): New function.
+ (start_decl): Use it. Remove dead code. Use add_decl_stmt.
+ (start_decl_1): Remove dead code.
+ (cp_finish_decl): Remove DECL_STMT handling here. Don't use
+ pseudo_global_level_p.
+ (grokvardecl): Create DECL_LANG_SPECIFIC for a VAR_DECL in a
+ template.
+ (grokdeclarator): Likewise, for TYPE_DECLs. Don't use
+ pseudo_global_level_p.
+ * decl2.c (grokfield): Call push_template_decl for a TYPE_DECL in
+ a template.
+ (get_sentry): Use push_permanent_obstack.
+ * dump.c (dequeue_and_dump): Enable DECL_STMT.
+ * except.c (call_eh_info): Use push_permanent_obstack.
+ (build_eh_type_ref): Likewise.
+ (do_pop_exception): Likewise.
+ (expand_eh_spec): Likewise.
+ (alloc_eh_object): Likewise.
+ (expand_throw): Likewise.
+ * init.c (build_java_class_ref): Likewise.
+ * lex.c (get_time_identifier): Likewise.
+ (free_lang_decl_chain): Correct type.
+ (retrofit_lang_decl): Adjust accordingly.
+ (build_lang_field_decl): Likewise.
+ * lex.h (free_lang_decl_chain): Likewise.
+ * parse.y (lang_extdef): Don't use pseudo_global_level_p.
+ * parse.c: Regenerated.
+ * pt.c (tsubst_default_arguments): New function.
+ (retrieve_local_specialization): Likewise.
+ (register_local_specialization): Likewise.
+ (push_template_decl_real): Use DECL_IMPLICIT_TYPEDEF_P. Just use
+ pseudo_global_level_p to determine whether or not a template is
+ primary.
+ (lookup_template_class): Likewise. Use create_implicit_typedef.
+ (instantiate_class_template): Call tsubst_default_arguments for
+ member functions, if appropriate.
+ (tsubst_default_argument): New function.
+ (tsubst_decl): Use it. Change TYPE_DECL handling to match VAR_DECLs.
+ * search.c (at_function_scope_p): New function.
+ * semantics.c (finish_asm_stmt): Use push_permanent_obstack.
+ (finish_label_stmt): Likewise.
+ (add_decl_stmt): New function.
+ (begin_class_definition): Likewise.
+ (finish_typeof): Likewise.
+ * tree.c (copy_template_template_parm): Likewise.
+ (copy_to_permanent): Likewise.
+ (push_permanent_obstack): Define.
+ (mark_addressable): Use it.
+ * typeck.c (mark_addressable): Likewise.
+
1999-08-13 Gavin Romig-Koch <gavin@cygnus.com>
cp-tree.h (init_cplus_unsave): New.
tree fn;
{
if (fn && DECL_TEMPLATE_INFO (fn))
- {
- /* This default argument came from a template. Instantiate the
- default argument here, not in tsubst. In the case of
- something like:
-
- template <class T>
- struct S {
- static T t();
- void f(T = t());
- };
-
- we must be careful to do name lookup in the scope of S<T>,
- rather than in the current class. */
- if (DECL_CLASS_SCOPE_P (fn))
- pushclass (DECL_REAL_CONTEXT (fn), 2);
-
- arg = tsubst_expr (arg, DECL_TI_ARGS (fn), /*complain=*/1, NULL_TREE);
-
- if (DECL_CLASS_SCOPE_P (fn))
- popclass ();
-
- /* Make sure the default argument is reasonable. */
- arg = check_default_argument (type, arg);
- }
+ arg = tsubst_default_argument (fn, type, arg);
arg = break_out_target_exprs (arg);
add_method (type, fields, method)
tree type, *fields, method;
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
/* Setting the DECL_CONTEXT and DECL_CLASS_CONTEXT here is probably
redundant. */
DECL_CLASS_CONTEXT (value) = current_class_type;
DECL_ARTIFICIAL (value) = 1;
+ if (processing_template_decl)
+ value = push_template_decl (value);
+
saved_cas = current_access_specifier;
current_access_specifier = access_public_node;
finish_member_declaration (value);
DEFTREECODE (EXPR_STMT, "expr_stmt", 'e', 1)
DEFTREECODE (COMPOUND_STMT, "compound_stmt", 'e', 1)
-DEFTREECODE (DECL_STMT, "decl_stmt", 'e', 3)
+DEFTREECODE (DECL_STMT, "decl_stmt", 'e', 1)
DEFTREECODE (IF_STMT, "if_stmt", 'e', 3)
DEFTREECODE (FOR_STMT, "for_stmt", 'e', 4)
DEFTREECODE (WHILE_STMT, "while_stmt", 'e', 2)
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
+ DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
3: DECL_IN_AGGR_P.
4: DECL_MAYBE_TEMPLATE.
5: DECL_INTERFACE_KNOWN.
tree access;
tree context;
- /* In a template FUNCTION_DECL, this is DECL_SAVED_TREE. */
- tree saved_tree;
-
union {
- /* In a FUNCTION_DECL, this is DECL_TEMPLATE_INFO. */
+ /* In a FUNCTION_DECL or a VAR_DECL, this is DECL_TEMPLATE_INFO. */
tree template_info;
/* In a NAMESPACE_DECL, this is NAMESPACE_LEVEL. */
tree main_decl_variant;
tree befriending_classes;
+
+ /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */
+ tree saved_tree;
+
union
{
tree sorted_fields;
struct pending_inline *pending_inline_info;
+ /* The lang_decls on the free_lang_decl_chain are chained together
+ through this pointer. */
+ struct lang_decl *next;
} u;
};
/* In a template FUNCTION_DECL, the tree structure that will be
substituted into to obtain instantiations. */
#define DECL_SAVED_TREE(NODE) \
- (DECL_LANG_SPECIFIC ((NODE))->decl_flags.saved_tree)
+ (DECL_LANG_SPECIFIC ((NODE))->saved_tree)
#define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE)
#define NEW_EXPR_USE_GLOBAL(NODE) TREE_LANG_FLAG_0 (NODE)
#define DECL_DECLARES_TYPE_P(NODE) \
(TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE))
+/* Nonzero if NODE is the typedef implicitly generated for a type when
+ the type is declared. (In C++, `struct S {};' is roughly equivalent
+ to `struct S {}; typedef struct S S;' in C. This macro will hold
+ for the typedef indicated in this example. Note that in C++, there
+ is a second implicit typedef for each class, in the scope of `S'
+ itself, so that you can `S::S'. This macro does *not* hold for
+ those typedefs. */
+#define DECL_IMPLICIT_TYPEDEF_P(NODE) \
+ (TREE_CODE ((NODE)) == TYPE_DECL && DECL_LANG_FLAG_2 ((NODE)))
+#define SET_DECL_IMPLICIT_TYPEDEF_P(NODE) \
+ (DECL_LANG_FLAG_2 ((NODE)) = 1)
+
/* A `primary' template is one that has its own template header. A
member function of a class template is a template, but not primary.
A member template is primary. Friend templates are primary, too. */
#define ASM_OUTPUTS(NODE) TREE_OPERAND (NODE, 2)
#define ASM_INPUTS(NODE) TREE_OPERAND (NODE, 3)
#define ASM_CLOBBERS(NODE) TREE_OPERAND (NODE, 4)
+#define DECL_STMT_DECL(NODE) TREE_OPERAND (NODE, 0)
/* Nonzero for an ASM_STMT if the assembly statement is volatile. */
#define ASM_VOLATILE_P(NODE) \
void *));
extern int wrapup_globals_for_namespace PROTO((tree, void *));
extern tree cp_namespace_decls PROTO((tree));
+extern tree create_implicit_typedef PROTO((tree, tree));
+extern tree maybe_push_decl PROTO((tree));
/* in decl2.c */
extern int check_java_method PROTO((tree));
extern tree instantiate_decl PROTO((tree));
extern tree do_poplevel PROTO((void));
extern tree get_bindings PROTO((tree, tree, tree));
-/* CONT ... */
extern void add_tree PROTO((tree));
extern void begin_tree PROTO((void));
extern void end_tree PROTO((void));
extern tree most_specialized_instantiation PROTO((tree, tree));
extern void print_candidates PROTO((tree));
extern int instantiate_pending_templates PROTO((void));
+extern tree tsubst_default_argument PROTO((tree, tree, tree));
extern int processing_specialization;
extern int processing_explicit_instantiation;
extern void init_search_processing PROTO((void));
extern void reinit_search_statistics PROTO((void));
extern tree current_scope PROTO((void));
+extern int at_function_scope_p PROTO((void));
extern tree lookup_conversions PROTO((tree));
extern tree binfo_for_vtable PROTO((tree));
extern int binfo_from_vbase PROTO((tree));
extern void finish_member_declaration PROTO((tree));
extern void check_multiple_declarators PROTO((void));
extern tree finish_typeof PROTO((tree));
+extern void add_decl_stmt PROTO((tree));
/* in spew.c */
extern void init_spew PROTO((void));
extern tree no_linkage_check PROTO((tree));
extern void debug_binfo PROTO((tree));
extern void push_expression_obstack PROTO((void));
+extern void push_permanent_obstack PROTO((void));
extern tree build_dummy_object PROTO((tree));
extern tree maybe_dummy_object PROTO((tree, tree *));
extern int is_dummy_object PROTO((tree));
int
pseudo_global_level_p ()
{
- struct binding_level *b = innermost_nonclass_level ();
-
- return b->pseudo_global;
+ return current_binding_level->pseudo_global;
}
void
if (!free_binding_nodes)
{
/* There are no free nodes, so we must build one here. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
binding = make_node (CPLUS_BINDING);
pop_obstacks ();
}
return decl;
}
+/* In C++, you don't have to write `struct S' to refer to `S'; you
+ can just use `S'. We accomplish this by creating a TYPE_DECL as
+ if the user had written `typedef struct S S'. Create and return
+ the TYPE_DECL for TYPE. */
+
+tree
+create_implicit_typedef (name, type)
+ tree name;
+ tree type;
+{
+ tree decl;
+
+ decl = build_decl (TYPE_DECL, name, type);
+ SET_DECL_ARTIFICIAL (decl);
+ /* There are other implicit type declarations, like the one *within*
+ a class that allows you to write `S::S'. We must distinguish
+ amongst these. */
+ SET_DECL_IMPLICIT_TYPEDEF_P (decl);
+ TYPE_NAME (type) = decl;
+
+ return decl;
+}
+
/* Push a tag name NAME for struct/class/union/enum type TYPE.
Normally put it into the inner-most non-tag-transparent scope,
but if GLOBALIZE is true, put it in the inner-most non-class scope.
{
register tree d = NULL_TREE;
int in_class = 0;
- tree context;
+ tree context = TYPE_CONTEXT (type);
- context = type ? TYPE_CONTEXT (type) : NULL_TREE;
if (! context)
{
tree cs = current_scope ();
|| b->parm_flag == 2)
in_class = 1;
- d = build_decl (TYPE_DECL, name, type);
if (current_lang_name == lang_name_java)
TYPE_FOR_JAVA (type) = 1;
- SET_DECL_ARTIFICIAL (d);
- if (! in_class)
- set_identifier_type_value_with_scope (name, type, b);
- TYPE_NAME (type) = d;
+ d = create_implicit_typedef (name, type);
DECL_CONTEXT (d) = FROB_CONTEXT (context);
+ if (! in_class)
+ set_identifier_type_value_with_scope (name, type, b);
d = maybe_process_template_type_declaration (type,
globalize, b);
if (oldtype)
push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
else
- {
- push_obstacks_nochange ();
- end_temporary_allocation ();
- }
+ push_permanent_obstack ();
/* Merge the data types specified in the two decls. */
newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
{
if (DECL_MAIN_VARIANT (olddecl) == olddecl)
{
- /* Save these lang_decls that would otherwise be lost. */
- extern tree free_lang_decl_chain;
- tree free_lang_decl = (tree) ol;
+ struct lang_decl *free_lang_decl = ol;
+ /* Save these lang_decls that would otherwise be lost. */
if (DECL_LANG_SPECIFIC (olddecl) == ol)
abort ();
- TREE_CHAIN (free_lang_decl) = free_lang_decl_chain;
+ free_lang_decl->u.next = free_lang_decl_chain;
free_lang_decl_chain = free_lang_decl;
}
else
}
}
+/* Enter DECL into the symbol table, if that's appropriate. Returns
+ DECL, or a modified version thereof. */
+
+tree
+maybe_push_decl (decl)
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+
+ /* Add this decl to the current binding level, but not if it comes
+ from another scope, e.g. a static member variable. TEM may equal
+ DECL or it may be a previous decl of the same name. */
+ if ((TREE_CODE (decl) != PARM_DECL
+ && DECL_CONTEXT (decl) != NULL_TREE
+ /* Definitions of namespace members outside their namespace are
+ possible. */
+ && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
+ || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ())
+ || TREE_CODE (type) == UNKNOWN_TYPE
+ /* The declaration of template specializations does not affect
+ the functions available for overload resolution, so we do not
+ call pushdecl. */
+ || (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_TEMPLATE_SPECIALIZATION (decl)))
+ return decl;
+ else
+ return pushdecl (decl);
+}
+
#if 0
/* This function is used to push the mangled decls for nested types into
the appropriate scope. Previously pushdecl_top_level was used, but that
decl);
}
- /* Add this decl to the current binding level, but not if it
- comes from another scope, e.g. a static member variable.
- TEM may equal DECL or it may be a previous decl of the same name. */
-
- if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE
- /* Definitions of namespace members outside their namespace are
- possible. */
- && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
- || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ())
- || TREE_CODE (type) == LANG_TYPE
- /* The declaration of template specializations does not affect
- the functions available for overload resolution, so we do not
- call pushdecl. */
- || (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_TEMPLATE_SPECIALIZATION (decl)))
- tem = decl;
- else
- tem = pushdecl (decl);
+ /* Enter this declaration into the symbol table. */
+ tem = maybe_push_decl (decl);
if (processing_template_decl)
{
- if (! current_function_decl)
- tem = push_template_decl (tem);
- else
- DECL_VINDEX (tem)
- = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
- copy_to_permanent (declspecs),
- NULL_TREE);
+ if (at_function_scope_p ())
+ push_permanent_obstack ();
+
+ tem = push_template_decl (tem);
+ /* In a a local scope, add a representation of this declaration
+ to the statement tree. */
+ if (at_function_scope_p ())
+ {
+ add_decl_stmt (decl);
+ pop_obstacks ();
+ }
}
/* Corresponding pop_obstacks is done in `cp_finish_decl'. */
push_obstacks_nochange ();
-#if 0
- /* We have no way of knowing whether the initializer will need to be
- evaluated at run-time or not until we've parsed it, so let's just put
- it in the permanent obstack. (jason) */
- if (init_written
- && ! (TREE_CODE (tem) == PARM_DECL
- || (TREE_READONLY (tem)
- && (TREE_CODE (tem) == VAR_DECL
- || TREE_CODE (tem) == FIELD_DECL))))
- {
- /* When parsing and digesting the initializer,
- use temporary storage. Do this even if we will ignore the value. */
- if (toplevel_bindings_p () && debug_temp_inits)
- {
- if (processing_template_decl
- || TYPE_NEEDS_CONSTRUCTING (type)
- || TREE_CODE (type) == REFERENCE_TYPE)
- /* In this case, the initializer must lay down in permanent
- storage, since it will be saved until `finish_file' is run. */
- ;
- else
- temporary_allocation ();
- }
- }
-#endif
-
return tem;
}
}
}
-#if 0
- /* We don't do this yet for GNU C++. */
- /* For a local variable, define the RTL now. */
- if (! toplevel_bindings_p ()
- /* But not if this is a duplicate decl
- and we preserved the rtl from the previous one
- (which may or may not happen). */
- && DECL_RTL (tem) == NULL_RTX)
- {
- if (TYPE_SIZE (TREE_TYPE (tem)) != NULL_TREE)
- expand_decl (tem);
- else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
- && DECL_INITIAL (tem) != NULL_TREE)
- expand_decl (tem);
- }
-#endif
-
if (! initialized)
DECL_INITIAL (decl) = NULL_TREE;
}
if (processing_template_decl)
{
if (init && DECL_INITIAL (decl))
- DECL_INITIAL (decl) = init;
- if (current_function_decl && ! DECL_ARTIFICIAL (decl))
- {
- tree stmt = DECL_VINDEX (decl);
- /* If the decl is declaring a member of a local class (in a
- template function), the DECL_VINDEX will either be NULL,
- or it will be an actual virtual function index, not a
- DECL_STMT. */
- if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT)
- {
- DECL_VINDEX (decl) = NULL_TREE;
- TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
- add_tree (stmt);
- }
- }
-
+ DECL_INITIAL (decl) = copy_to_permanent (init);
goto finish_end0;
}
else if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (TREE_STATIC (decl))
- make_decl_rtl (decl, NULL_PTR,
- toplevel_bindings_p ()
- || pseudo_global_level_p ());
+ make_decl_rtl (decl, NULL_PTR, toplevel_bindings_p ());
grok_reference_init (decl, type, init);
init = NULL_TREE;
}
|| TREE_CODE (decl) == RESULT_DECL)
{
/* ??? FIXME: What about nested classes? */
- int toplev = toplevel_bindings_p () || pseudo_global_level_p ();
+ int toplev = toplevel_bindings_p ();
int was_temp
= (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
&& allocation_temporary_p ());
else
context = NULL_TREE;
- decl = build_decl (VAR_DECL, declarator, complete_type (type));
+ if (processing_template_decl)
+ {
+ /* If we're in a template, we need DECL_LANG_SPECIFIC so that
+ we can call push_template_decl. */
+ push_permanent_obstack ();
+ decl = build_lang_field_decl (VAR_DECL, declarator,
+ complete_type (type));
+ pop_obstacks ();
+ }
+ else
+ decl = build_decl (VAR_DECL, declarator, complete_type (type));
if (context)
set_decl_namespace (decl, context, 0);
We also want to avoid calling this a PARM if it is in a namespace. */
- if (decl_context == NORMAL && ! namespace_bindings_p ()
- && ! pseudo_global_level_p ())
+ if (decl_context == NORMAL && !toplevel_bindings_p ())
{
struct binding_level *b = current_binding_level;
current_binding_level = b->level_chain;
since it might be used as a template parameter. */
if (type != error_mark_node)
push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
- decl = build_decl (TYPE_DECL, declarator, type);
+ if (processing_template_decl)
+ decl = build_lang_field_decl (TYPE_DECL, declarator, type);
+ else
+ decl = build_decl (TYPE_DECL, declarator, type);
if (type != error_mark_node)
pop_obstacks ();
}
- /* If the user declares "struct {...} foo" then `foo' will have
- an anonymous name. Fill that name in now. Nothing can
- refer to it, so nothing needs know about the name change.
- The TYPE_NAME field was filled in by build_struct_xref. */
+ /* If the user declares "typedef struct {...} foo" then the
+ struct will have an anonymous name. Fill that name in now.
+ Nothing can refer to it, so nothing needs know about the name
+ change. */
if (type != error_mark_node
&& TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
{
/* C++ allows static class members.
All other work for this is done by grokfield.
- This VAR_DCL is built by build_lang_field_decl.
+ This VAR_DECL is built by build_lang_field_decl.
All other VAR_DECLs are built by build_decl. */
decl = build_lang_field_decl (VAR_DECL, declarator, type);
TREE_STATIC (decl) = 1;
if (pre_parsed_p == 2)
maybe_begin_member_template_processing (decl1);
+ /* Effective C++ rule 15. See also c_expand_return. */
+ if (warn_ecpp
+ && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
+ && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
+ cp_warning ("`operator=' should return a reference to `*this'");
+
+ /* Make the init_value nonzero so pushdecl knows this is not tentative.
+ error_mark_node is replaced below (in poplevel) with the BLOCK. */
+ DECL_INITIAL (decl1) = error_mark_node;
+
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+ SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
+#endif
+
+ /* This function exists in static storage.
+ (This does not mean `static' in the C sense!) */
+ TREE_STATIC (decl1) = 1;
+
+ /* We must call push_template_decl after current_class_type is set
+ up. (If we are processing inline definitions after exiting a
+ class scope, current_class_type will be NULL_TREE until set above
+ by push_nested_class.) */
+ if (processing_template_decl)
+ decl1 = push_template_decl (decl1);
+
/* We are now in the scope of the function being defined. */
current_function_decl = decl1;
abstract_virtuals_error (decl1, TREE_TYPE (fntype));
}
- /* Effective C++ rule 15. See also c_expand_return. */
- if (warn_ecpp
- && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
- && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
- cp_warning ("`operator=' should return a reference to `*this'");
-
- /* Make the init_value nonzero so pushdecl knows this is not tentative.
- error_mark_node is replaced below (in poplevel) with the BLOCK. */
- DECL_INITIAL (decl1) = error_mark_node;
-
-#ifdef SET_DEFAULT_DECL_ATTRIBUTES
- SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
-#endif
-
- /* This function exists in static storage.
- (This does not mean `static' in the C sense!) */
- TREE_STATIC (decl1) = 1;
-
- /* We must call push_template_decl after current_class_type is set
- up. (If we are processing inline definitions after exiting a
- class scope, current_class_type will be NULL_TREE until set above
- by push_nested_class.) */
- if (processing_template_decl)
- decl1 = push_template_decl (decl1);
-
/* Record the decl so that the function name is defined.
If we already have a decl for this name, and it is a FUNCTION_DECL,
use the old decl. */
DECL_ASSEMBLER_NAME (value) =
get_identifier (build_overload_name (TREE_TYPE (value), 1, 1));
+ if (processing_template_decl)
+ value = push_template_decl (value);
+
return value;
}
tree sentry = IDENTIFIER_GLOBAL_VALUE (sname);
if (! sentry)
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
sentry = build_decl (VAR_DECL, sname, integer_type_node);
TREE_PUBLIC (sentry) = 1;
DECL_ARTIFICIAL (sentry) = 1;
case DECL_STMT:
dump_stmt (di, t);
-#if 0
- /* We do not yet have DECL_STMT_DECL; there are declarators and
- such hanging about in DECL_STMTs. */
if (dump_children_p)
dump_child ("decl", DECL_STMT_DECL (t));
-#endif
break;
case DO_STMT:
/* Declare cp_eh_info * __start_cp_handler (void),
as defined in exception.cc. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
/* struct cp_eh_info. This must match exception.cc. Note that this
type is not pushed anywhere. */
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
if (flag_rtti)
{
{
/* Declare void __cp_pop_exception (void *),
as defined in exception.cc. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
fn = build_lang_decl
(FUNCTION_DECL, fn,
build_function_type (void_type_node, tree_cons
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
tmp = tree_cons
(NULL_TREE, integer_type_node, tree_cons
{
/* Declare __eh_alloc (size_t), as defined in exception.cc. */
tree tmp;
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
fn = build_lang_decl (FUNCTION_DECL, fn,
build_function_type (ptr_type_node, tmp));
the internal type of a destructor. */
if (cleanup_type == NULL_TREE)
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
cleanup_type = build_pointer_type
(build_function_type
(void_type_node, tree_cons
/* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
as defined in exception.cc. */
tree tmp;
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
tmp = tree_cons
(NULL_TREE, ptr_type_node, tree_cons
(NULL_TREE, ptr_type_node, tree_cons
{
/* Declare void __uncatch_exception (void)
as defined in exception.cc. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
fn = build_lang_decl (FUNCTION_DECL, fn,
build_function_type (void_type_node,
void_list_node));
class_decl = IDENTIFIER_GLOBAL_VALUE (name);
if (class_decl == NULL_TREE)
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
TREE_STATIC (class_decl) = 1;
DECL_EXTERNAL (class_decl) = 1;
time_identifier = get_identifier (buf);
if (TIME_IDENTIFIER_TIME (time_identifier) == NULL_TREE)
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
TIME_IDENTIFIER_TIME (time_identifier) = build_int_2 (0, 0);
TIME_IDENTIFIER_FILEINFO (time_identifier)
= build_int_2 (0, 1);
#endif
/* Place to save freed lang_decls which were allocated on the
- permanent_obstack. @@ Not currently used. */
-tree free_lang_decl_chain;
+ permanent_obstack. */
+struct lang_decl *free_lang_decl_chain;
tree
build_lang_decl (code, name, type)
tree t;
{
struct obstack *obstack = current_obstack;
- register int i = sizeof (struct lang_decl) / sizeof (int);
- register int *pi;
+ struct lang_decl *ld;
if (! TREE_PERMANENT (t))
obstack = saveable_obstack;
if (free_lang_decl_chain && obstack == &permanent_obstack)
{
- pi = (int *)free_lang_decl_chain;
- free_lang_decl_chain = TREE_CHAIN (free_lang_decl_chain);
+ ld = free_lang_decl_chain;
+ free_lang_decl_chain = free_lang_decl_chain->u.next;
}
else
- pi = (int *) obstack_alloc (obstack, sizeof (struct lang_decl));
+ ld = ((struct lang_decl *)
+ obstack_alloc (obstack, sizeof (struct lang_decl)));
- while (i > 0)
- pi[--i] = 0;
+ bzero (ld, sizeof (struct lang_decl));
- DECL_LANG_SPECIFIC (t) = (struct lang_decl *) pi;
- LANG_DECL_PERMANENT ((struct lang_decl *) pi)
- = obstack == &permanent_obstack;
- my_friendly_assert (LANG_DECL_PERMANENT ((struct lang_decl *) pi)
- == TREE_PERMANENT (t), 234);
+ DECL_LANG_SPECIFIC (t) = ld;
+ LANG_DECL_PERMANENT (ld) = obstack == &permanent_obstack;
+ my_friendly_assert (LANG_DECL_PERMANENT (ld) == TREE_PERMANENT (t), 234);
DECL_MAIN_VARIANT (t) = t;
if (current_lang_name == lang_name_cplusplus)
DECL_LANGUAGE (t) = lang_cplusplus;
DECL_LANGUAGE (t) = lang_java;
else my_friendly_abort (64);
-#if 0 /* not yet, should get fixed properly later */
- if (code == TYPE_DECL)
- {
- tree id;
- id = get_identifier (build_overload_name (type, 1, 1));
- DECL_ASSEMBLER_NAME (t) = id;
- }
-
-#endif
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_decl] += 1;
tree_node_sizes[(int)lang_decl] += sizeof (struct lang_decl);
#endif
}
+/* Like build_decl, except that a new lang_decl_flags structure is
+ placed in DECL_LANG_SPECIFIC. */
+
tree
build_lang_field_decl (code, name, type)
enum tree_code code;
extern struct obstack *current_obstack, *saveable_obstack;
register tree t = build_decl (code, name, type);
struct obstack *obstack = current_obstack;
- register int i = sizeof (struct lang_decl_flags) / sizeof (int);
- register int *pi;
-#if 0 /* not yet, should get fixed properly later */
-
- if (code == TYPE_DECL)
- {
- tree id;
- id = get_identifier (build_overload_name (type, 1, 1));
- DECL_ASSEMBLER_NAME (t) = id;
- }
-#endif
if (! TREE_PERMANENT (t))
obstack = saveable_obstack;
else
my_friendly_assert (obstack == &permanent_obstack, 235);
- pi = (int *) obstack_alloc (obstack, sizeof (struct lang_decl_flags));
- while (i > 0)
- pi[--i] = 0;
-
- DECL_LANG_SPECIFIC (t) = (struct lang_decl *) pi;
+ DECL_LANG_SPECIFIC (t)
+ = ((struct lang_decl *)
+ obstack_alloc (obstack, sizeof (struct lang_decl_flags)));
+ bzero (DECL_LANG_SPECIFIC (t), sizeof (struct lang_decl_flags));
return t;
}
extern int pending_lang_change;
extern int yylex PROTO((void));
+
+extern struct lang_decl *free_lang_decl_chain;
break;}
case 13:
#line 386 "parse.y"
-{ if (! toplevel_bindings_p () && ! pseudo_global_level_p())
+{ if (! toplevel_bindings_p ())
pop_everything (); ;
break;}
case 14:
lang_extdef:
{ if (pending_lang_change) do_pending_lang_change(); }
extdef
- { if (! toplevel_bindings_p () && ! pseudo_global_level_p())
+ { if (! toplevel_bindings_p ())
pop_everything (); }
;
static int inline_needs_template_parms PROTO((tree));
static void push_inline_template_parms_recursive PROTO((tree, int));
static tree retrieve_specialization PROTO((tree, tree));
+static tree retrieve_local_specialization PROTO((tree, tree));
static tree register_specialization PROTO((tree, tree, tree));
+static tree register_local_specialization PROTO((tree, tree, tree));
static int unregister_specialization PROTO((tree, tree));
static tree reduce_template_parm_level PROTO((tree, tree, int));
static tree build_template_decl PROTO((tree, tree));
static tree determine_specialization PROTO((tree, tree, tree *, int));
static int template_args_equal PROTO((tree, tree));
static void print_template_context PROTO((int));
+static void tsubst_default_arguments PROTO((tree));
/* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the
return NULL_TREE;
}
+/* Like retrieve_speciailization, but for local declarations. FN is
+ the function in which we are looking for an instantiation. */
+
+static tree
+retrieve_local_specialization (tmpl, fn)
+ tree tmpl;
+ tree fn;
+{
+ tree s = purpose_member (fn, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+ return s ? TREE_VALUE (s) : NULL_TREE;
+}
+
/* Returns non-zero iff DECL is a specialization of TMPL. */
int
return 0;
}
+/* Like register_specialization, but for local declarations. FN is
+ the function in which we are registering SPEC, an instantiation of
+ TMPL. */
+
+static tree
+register_local_specialization (spec, tmpl, fn)
+ tree spec;
+ tree tmpl;
+ tree fn;
+{
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
+ = perm_tree_cons (fn, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+
+ return spec;
+}
+
/* Print the list of candidate FNS in an error message. */
void
int is_partial;
/* See if this is a partial specialization. */
- is_partial = (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
+ is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
else
/* Otherwise, if we're currently definining some class, the DECL
is assumed to be a member of the class. */
- ctx = current_class_type;
+ ctx = current_scope ();
if (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)
ctx = NULL_TREE;
if (!DECL_CONTEXT (decl))
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
- /* For determining whether this is a primary template or not, we're really
- interested in the lexical context, not the true context. */
- if (is_friend)
- info = current_class_type;
- else
- info = ctx;
-
/* See if this is a primary template. */
- if (info && TREE_CODE (info) == FUNCTION_DECL)
- primary = 0;
- /* Note that template_class_depth returns 0 if given NULL_TREE, so
- this next line works even when we are at global scope. */
- else if (processing_template_decl > template_class_depth (info))
- primary = 1;
- else
- primary = 0;
+ primary = pseudo_global_level_p ();
if (primary)
{
info = perm_tree_cons (tmpl, args, NULL_TREE);
- if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
+ if (DECL_IMPLICIT_TYPEDEF_P (decl))
{
SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
if ((!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
{
TYPE_CONTEXT (t) = FROB_CONTEXT (context);
- /* Create a stub TYPE_DECL for it. */
- type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t);
- SET_DECL_ARTIFICIAL (type_decl);
+ type_decl = create_implicit_typedef (DECL_NAME (template), t);
DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
-
+ TYPE_STUB_DECL (t) = type_decl;
DECL_SOURCE_FILE (type_decl)
= DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type));
DECL_SOURCE_LINE (type_decl)
= DECL_SOURCE_LINE (TYPE_STUB_DECL (template_type));
- TYPE_STUB_DECL (t) = TYPE_NAME (t) = type_decl;
}
else
type_decl = TYPE_NAME (t);
TYPE_BEING_DEFINED (type) = 0;
repo_template_used (type);
+ /* Now that the class is complete, instantiate default arguments for
+ any member functions. We don't do this earlier because the
+ default arguments may reference members of the class. */
+ if (!PRIMARY_TEMPLATE_P (template))
+ for (t = TYPE_METHODS (type); t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == FUNCTION_DECL
+ /* Implicitly generated member functions will not have tmplate
+ information; they are not instantiations, but instead are
+ created "fresh" for each instantiation. */
+ && DECL_TEMPLATE_INFO (t))
+ tsubst_default_arguments (t);
+
popclass ();
pop_from_top_level ();
pop_tinst_level ();
}
}
+/* Substitute into the default argument ARG (a default argument for
+ FN), which has the indicated TYPE. */
+
+tree
+tsubst_default_argument (fn, type, arg)
+ tree fn;
+ tree type;
+ tree arg;
+{
+ /* This default argument came from a template. Instantiate the
+ default argument here, not in tsubst. In the case of
+ something like:
+
+ template <class T>
+ struct S {
+ static T t();
+ void f(T = t());
+ };
+
+ we must be careful to do name lookup in the scope of S<T>,
+ rather than in the current class. */
+ if (DECL_CLASS_SCOPE_P (fn))
+ pushclass (DECL_REAL_CONTEXT (fn), 2);
+
+ arg = tsubst_expr (arg, DECL_TI_ARGS (fn), /*complain=*/1, NULL_TREE);
+
+ if (DECL_CLASS_SCOPE_P (fn))
+ popclass ();
+
+ /* Make sure the default argument is reasonable. */
+ arg = check_default_argument (type, arg);
+
+ return arg;
+}
+
+/* Substitute into all the default arguments for FN. */
+
+static void
+tsubst_default_arguments (fn)
+ tree fn;
+{
+ tree arg;
+ tree tmpl_args;
+
+ tmpl_args = DECL_TI_ARGS (fn);
+
+ /* If this function is not yet instantiated, we certainly don't need
+ its default arguments. */
+ if (uses_template_parms (tmpl_args))
+ return;
+
+ for (arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ arg;
+ arg = TREE_CHAIN (arg))
+ if (TREE_PURPOSE (arg))
+ TREE_PURPOSE (arg) = tsubst_default_argument (fn,
+ TREE_VALUE (arg),
+ TREE_PURPOSE (arg));
+}
+
/* Substitute the ARGS into the T, which is a _DECL. TYPE is the
(already computed) substitution of ARGS into TREE_TYPE (T), if
appropriate. Return the result of the substitution. IN_DECL is as
&& (IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r))
== NULL_TREE))
SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
+
+ /* We're not supposed to instantiate default arguments
+ until they are called, for a template. But, for a
+ declaration like:
+
+ template <class T> void f ()
+ { extern void g(int i = T()); }
+
+ we should do the substitution when the template is
+ instantiated. We handle the member function case in
+ instantiate_class_template since the default arguments
+ might refer to other members of the class. */
+ if (!member
+ && !PRIMARY_TEMPLATE_P (gen_tmpl)
+ && !uses_template_parms (argvec))
+ tsubst_default_arguments (r);
}
/* Copy the list of befriending classes. */
}
break;
+ case TYPE_DECL:
+ if (DECL_IMPLICIT_TYPEDEF_P (t))
+ {
+ /* For an implicit typedef, we just want the implicit
+ typedef for the tsubst'd type. We've already got the
+ tsubst'd type, as TYPE, so we just need it's associated
+ declaration. */
+ r = TYPE_NAME (type);
+ break;
+ }
+ else if (!DECL_LANG_SPECIFIC (t))
+ {
+ /* For a template type parameter, we don't have to do
+ anything special. */
+ r= TYPE_NAME (type);
+ break;
+ }
+
+ /* Fall through. */
+
case VAR_DECL:
{
tree argvec;
tree gen_tmpl;
tree spec;
tree tmpl;
- tree ctx = tsubst_aggr_type (DECL_CONTEXT (t), args,
- /*complain=*/1,
- in_decl, /*entering_scope=*/1);
-
+ tree ctx;
+
/* Nobody should be tsubst'ing into non-template variables. */
my_friendly_assert (DECL_LANG_SPECIFIC (t)
&& DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
+ if (TYPE_P (DECL_CONTEXT (t)))
+ ctx = tsubst_aggr_type (DECL_CONTEXT (t), args,
+ /*complain=*/1,
+ in_decl, /*entering_scope=*/1);
+ else
+ /* Subsequent calls to pushdecl will fill this in. */
+ ctx = NULL_TREE;
+
/* Check to see if we already have this specialization. */
tmpl = DECL_TI_TEMPLATE (t);
gen_tmpl = most_general_template (tmpl);
argvec = tsubst (DECL_TI_ARGS (t), args, /*complain=*/1, in_decl);
- spec = retrieve_specialization (gen_tmpl, argvec);
-
+ if (ctx)
+ spec = retrieve_specialization (gen_tmpl, argvec);
+ else
+ spec = retrieve_local_specialization (gen_tmpl,
+ current_function_decl);
+
if (spec)
{
r = spec;
DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r);
- register_specialization (r, gen_tmpl, argvec);
+ if (ctx)
+ register_specialization (r, gen_tmpl, argvec);
+ else
+ register_local_specialization (r, gen_tmpl,
+ current_function_decl);
TREE_CHAIN (r) = NULL_TREE;
- if (TREE_CODE (type) == VOID_TYPE)
+ if (TREE_CODE (r) == VAR_DECL && TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
}
break;
- case TYPE_DECL:
- if (t == TYPE_NAME (TREE_TYPE (t)))
- r = TYPE_NAME (type);
- else
- {
- r = copy_node (t);
- TREE_TYPE (r) = type;
- DECL_CONTEXT (r) = current_class_type;
- TREE_CHAIN (r) = NULL_TREE;
- }
- break;
-
default:
my_friendly_abort (0);
}
return t;
/* Unfortunately, we cannot just call lookup_name here.
- Consider:
-
- template <int I> int f() {
- enum E { a = I };
- struct S { void g() { E e = a; } };
- };
-
- When we instantiate f<7>::S::g(), say, lookup_name is not
- clever enough to find f<7>::a. */
+ Consider:
+
+ template <int I> int f() {
+ enum E { a = I };
+ struct S { void g() { E e = a; } };
+ };
+
+ When we instantiate f<7>::S::g(), say, lookup_name is not
+ clever enough to find f<7>::a. */
enum_type
= tsubst_aggr_type (TREE_TYPE (t), args, complain, in_decl,
/*entering_scope=*/0);
return current_class_type;
}
+/* Returns non-zero if we are currently in a function scope. Note
+ that this function returns zero if we are within a local class, but
+ not within a member function body of the local class. */
+
+int
+at_function_scope_p ()
+{
+ tree cs = current_scope ();
+ return cs && TREE_CODE (cs) == FUNCTION_DECL;
+}
+
/* Return the scope of DECL, as appropriate when doing name-lookup. */
static tree
return binfo;
}
-/* Within the scope of a template class, you can refer to the
- particular to the current specialization with the name of the
- template itself. For example:
+/* Within the scope of a template class, you can refer to the to the
+ current specialization with the name of the template itself. For
+ example:
template <typename T> struct S { S* sp; }
if (TREE_CHAIN (string))
{
if (processing_template_decl)
- {
- /* We need to build the combined string on the permanent
- obstack so that we can use it during instantiations. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
- }
+ /* We need to build the combined string on the permanent
+ obstack so that we can use it during instantiations. */
+ push_permanent_obstack ();
string = combine_strings (string);
if (processing_template_decl)
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
decl = build_decl (LABEL_DECL, name, void_type_node);
pop_obstacks ();
DECL_SOURCE_LINE (decl) = lineno;
}
}
+/* Create a declaration statement for the declaration given by the
+ DECL. */
+
+void
+add_decl_stmt (decl)
+ tree decl;
+{
+ tree decl_stmt;
+
+ /* We need the type to last until instantiation time. */
+ TREE_TYPE (decl) = copy_to_permanent (TREE_TYPE (decl));
+ decl_stmt = build_min_nt (DECL_STMT, decl);
+ add_tree (decl_stmt);
+}
+
/* Finish a parenthesized expression EXPR. */
tree
begin_class_definition (t)
tree t;
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
+ push_permanent_obstack ();
+
if (t == error_mark_node
|| ! IS_AGGR_TYPE (t))
{
{
tree t;
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
+ push_permanent_obstack ();
t = make_lang_type (TYPEOF_TYPE);
TYPE_FIELDS (t) = expr;
-
pop_obstacks ();
return t;
push_obstacks_nochange ();
- /* We need a new one. If both ELT_TYPE and INDEX_TYPE are permanent,
+ /* If both ELT_TYPE and INDEX_TYPE are permanent,
make this permanent too. */
if (TREE_PERMANENT (elt_type)
&& (index_type == 0 || TREE_PERMANENT (index_type)))
tree t2;
/* Make sure these end up on the permanent_obstack. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
template = copy_node (template);
if (t == NULL_TREE || TREE_PERMANENT (t))
return t;
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
+ push_permanent_obstack ();
t = mapcar (t, perm_manip);
-
pop_obstacks ();
return t;
current_obstack = expression_obstack;
}
+/* Begin allocating on the permanent obstack. When you're done
+ allocating there, call pop_obstacks to return to the previous set
+ of obstacks. */
+
+void
+push_permanent_obstack ()
+{
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+}
+
/* The type of ARG when used as an lvalue. */
tree
{
/* We thought this would make a good constant variable,
but we were wrong. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
TREE_ASM_WRITTEN (x) = 0;
DECL_RTL (x) = 0;
public:
A() {}
- A(const A<T>& b) {} // ERROR - invalid use of template
+ A(const A<T>& b) {}
};
--- /dev/null
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+template <class T = int>
+struct S
+{
+ void f ()
+ {
+ struct U {
+ };
+ }
+};
--- /dev/null
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+template <class T>
+void f (int i)
+{
+ struct S { void g (int j = i) {} }; // ERROR - default argument uses local
+
+ S s; // ERROR - instantiated here
+}
+
+template void f<double>(int); // ERROR - instantiated here
+