diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 21d670c7663..9b560266f33 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2000-10-30 Mark Mitchell + + * cp-tree.h (DECL_EXTERNAL_LINKAGE_P): New macro. + (linkage_kind): New enumeration. + (decl_linkage): New function. + * decl2.c (comdat_linkage): Extend comment. + * error.c (dump_function_decl): Print the arguments used to + instantiate a template, even when not printing the type of the + function. + * pt.c (convert_nontype_argument): Use DECL_EXTERNAL_LINKAGE_P, + not TREE_PUBLIC, to test for external linkage. + * tree.c (decl_linkage): New function. + 2000-10-28 Mark Mitchell * pt.c (instantiate_decl): Always instantiate static data members diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 54dbaa34da5..fc3cd86934d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2498,6 +2498,13 @@ extern int flag_new_for_scope; #define DECL_UNINLINABLE(NODE) \ (DECL_LANG_SPECIFIC (NODE)->decl_flags.uninlinable) +/* Returns non-zero if DECL has external linkage, as specified by the + language standard. (This predicate may hold even when the + corresponding entity is not actually given external linkage in the + object file; see decl_linkage for details.) */ +#define DECL_EXTERNAL_LINKAGE_P(DECL) \ + (decl_linkage (DECL) == lk_external) + #define INTEGRAL_CODE_P(CODE) \ (CODE == INTEGER_TYPE || CODE == ENUMERAL_TYPE || CODE == BOOLEAN_TYPE) @@ -3145,6 +3152,29 @@ typedef enum special_function_kind { sfk_conversion /* A conversion operator. */ } special_function_kind; +/* The various kinds of linkage. From [basic.link], + + A name is said to have linkage when it might denote the same + object, reference, function, type, template, namespace or value + as a name introduced in another scope: + + -- When a name has external linkage, the entity it denotes can + be referred to from scopes of other translation units or from + other scopes of the same translation unit. + + -- When a name has internal linkage, the entity it denotes can + be referred to by names from other scopes in the same + translation unit. + + -- When a name has no linkage, the entity it denotes cannot be + referred to by names from other scopes. */ + +typedef enum linkage_kind { + lk_none, /* No linkage. */ + lk_internal, /* Internal linkage. */ + lk_external /* External linkage. */ +} linkage_kind; + /* Bitmask flags to pass to instantiate_type. */ typedef enum instantiate_type_flags { itf_none = 0, /* nothing special */ @@ -4443,6 +4473,7 @@ extern int count_trees PARAMS ((tree)); extern int char_type_p PARAMS ((tree)); extern void verify_stmt_tree PARAMS ((tree)); extern tree find_tree PARAMS ((tree, tree)); +extern linkage_kind decl_linkage PARAMS ((tree)); /* in typeck.c */ extern int string_conv_p PARAMS ((tree, tree, int)); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 766b45f8ac7..0cfcc4dee58 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2427,8 +2427,13 @@ comdat_linkage (decl) if (flag_weak) make_decl_one_only (decl); else if (TREE_CODE (decl) == FUNCTION_DECL || DECL_VIRTUAL_P (decl)) - /* We can just emit functions and vtables statically; it doesn't really - matter if we have multiple copies. */ + /* We can just emit functions and vtables statically; having + multiple copies is (for the most part) only a waste of space. + There is at least one correctness issue, however: the address + of a template instantiation with external linkage should be the + same, independent of what translation unit asks for the + address, and this will not hold when we emit multiple copies of + the function. However, there's little else we can do. */ TREE_PUBLIC (decl) = 0; else { diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 91c9f6e9f06..6e7a4ae3245 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1284,27 +1284,28 @@ dump_function_decl (t, flags) dump_function_name (t, flags); - if (!(flags & TS_DECL_TYPE)) - return; - if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes) - /* Skip "this" parameter. */ - parmtypes = TREE_CHAIN (parmtypes); + if (flags & TS_DECL_TYPE) + { + if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes) + /* Skip "this" parameter. */ + parmtypes = TREE_CHAIN (parmtypes); - /* Skip past the "in_charge" parameter. */ - if (DECL_HAS_IN_CHARGE_PARM_P (t)) - parmtypes = TREE_CHAIN (parmtypes); + /* Skip past the "in_charge" parameter. */ + if (DECL_HAS_IN_CHARGE_PARM_P (t)) + parmtypes = TREE_CHAIN (parmtypes); - dump_parameters (parmtypes, flags); + dump_parameters (parmtypes, flags); - if (show_return) - dump_type_suffix (TREE_TYPE (fntype), flags); + if (show_return) + dump_type_suffix (TREE_TYPE (fntype), flags); - if (TREE_CODE (fntype) == METHOD_TYPE) - dump_qualifiers (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))), - before); + if (TREE_CODE (fntype) == METHOD_TYPE) + dump_qualifiers (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))), + before); - if (flags & TS_FUNC_THROW) - dump_exception_spec (TYPE_RAISES_EXCEPTIONS (fntype), flags); + if (flags & TS_FUNC_THROW) + dump_exception_spec (TYPE_RAISES_EXCEPTIONS (fntype), flags); + } /* If T is a template instantiation, dump the parameter binding. */ if (template_parms != NULL_TREE && template_args != NULL_TREE) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8ca2468a0b2..303a3c65bec 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2808,7 +2808,7 @@ convert_nontype_argument (type, expr) ; else if (TREE_CODE (referent) != VAR_DECL) goto bad_argument; - else if (!TREE_PUBLIC (referent)) + else if (!DECL_EXTERNAL_LINKAGE_P (referent)) { cp_error ("address of non-extern `%E' cannot be used as template argument", referent); return error_mark_node; @@ -2915,7 +2915,7 @@ convert_nontype_argument (type, expr) if (fn == error_mark_node) return error_mark_node; - if (!TREE_PUBLIC (fn)) + if (!DECL_EXTERNAL_LINKAGE_P (fn)) { if (really_overloaded_fn (fns)) return error_mark_node; @@ -2980,7 +2980,7 @@ convert_nontype_argument (type, expr) if (fn == error_mark_node) return error_mark_node; - if (!TREE_PUBLIC (fn)) + if (!DECL_EXTERNAL_LINKAGE_P (fn)) { if (really_overloaded_fn (expr)) /* Don't issue an error here; we might get a different diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index d6314d81968..db5e33deee5 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2597,3 +2597,46 @@ char_type_p (type) || same_type_p (type, signed_char_type_node) || same_type_p (type, wchar_type_node)); } + +/* Returns the kind of linkage associated with the indicated DECL. Th + value returned is as specified by the language standard; it is + independent of implementation details regarding template + instantiation, etc. For example, it is possible that a declaration + to which this function assigns external linkage would not show up + as a global symbol when you run `nm' on the resulting object file. */ + +linkage_kind +decl_linkage (decl) + tree decl; +{ + /* This function doesn't attempt to calculate the linkage from first + principles as given in [basic.link]. Instead, it makes use of + the fact that we have already set TREE_PUBLIC appropriately, and + then handles a few special cases. Ideally, we would calculate + linkage first, and then transform that into a concrete + implementation. */ + + /* Things that don't have names have no linkage. */ + if (!DECL_NAME (decl)) + return lk_none; + + /* Things that are TREE_PUBLIC have external linkage. */ + if (TREE_PUBLIC (decl)) + return lk_external; + + /* Some things that are not TREE_PUBLIC have external linkage, too. + For example, on targets that don't have weak symbols, we make all + template instantiations have internal linkage (in the object + file), but the symbols should still be treated as having external + linkage from the point of view of the language. */ + if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl)) + return lk_external; + + /* Things in local scope do not have linkage, if they don't have + TREE_PUBLIC set. */ + if (decl_function_context (decl)) + return lk_none; + + /* Everything else has internal linkage. */ + return lk_internal; +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/linkage6.C b/gcc/testsuite/g++.old-deja/g++.other/linkage6.C new file mode 100644 index 00000000000..65374ca6bd3 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/linkage6.C @@ -0,0 +1,18 @@ +// Build don't link: +// Special g++ Options: -fno-weak +// Origin: Mark Mitchell + +template +void f (); + +void h () { f (); } + +template +void g () {} + +template +void f () +{ + g<&f >(); +} +