diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9e3a63eeb5b..c4a81771a5b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,17 @@ 2014-02-25 Jason Merrill + PR c++/55877 + * decl2.c (no_linkage_error): Handle C++98 semantics. + (reset_type_linkage): Move from decl.c. + (reset_type_linkage_1, reset_type_linkage_2, bt_reset_linkage_1) + (bt_reset_linkage_2, reset_decl_linkage): New. + (tentative_decl_linkage): Factor out of expand_or_defer_fn_1. + (cp_write_global_declarations): Move condition into no_linkage_error. + * decl.c (grokfndecl, grokvardecl): Use no_linkage_error. + * semantics.c (expand_or_defer_fn_1): Factor out + tentative_decl_linkage. + * cp-tree.h: Adjust. + * decl2.c (finish_static_data_member_decl): Diagnose static data member in unnamed class. * class.c (finish_struct_anon_r): Avoid redundant diagnostic. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7681b27ca4d..3db18f3eaec 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5313,12 +5313,15 @@ extern tree coerce_delete_type (tree); extern void comdat_linkage (tree); extern void determine_visibility (tree); extern void constrain_class_visibility (tree); +extern void reset_type_linkage (tree); +extern void tentative_decl_linkage (tree); extern void import_export_decl (tree); extern tree build_cleanup (tree); extern tree build_offset_ref_call_from_tree (tree, vec **, tsubst_flags_t); extern bool decl_constant_var_p (tree); extern bool decl_maybe_constant_var_p (tree); +extern void no_linkage_error (tree); extern void check_default_args (tree); extern bool mark_used (tree); extern bool mark_used (tree, tsubst_flags_t); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 04c4cf515c3..db86d972783 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7569,29 +7569,7 @@ grokfndecl (tree ctype, declare an entity with linkage. DR 757 relaxes this restriction for C++0x. */ - t = no_linkage_check (TREE_TYPE (decl), - /*relaxed_p=*/false); - if (t) - { - if (TYPE_ANONYMOUS_P (t)) - { - if (DECL_EXTERN_C_P (decl)) - /* Allow this; it's pretty common in C. */; - else - { - permerror (input_location, "anonymous type with no linkage " - "used to declare function %q#D with linkage", - decl); - if (DECL_ORIGINAL_TYPE (TYPE_NAME (t))) - permerror (input_location, "%q+#D does not refer to the unqualified " - "type, so it is not used for linkage", - TYPE_NAME (t)); - } - } - else - permerror (input_location, "type %qT with no linkage used to " - "declare function %q#D with linkage", t, decl); - } + no_linkage_error (decl); } TREE_PUBLIC (decl) = publicp; @@ -7874,7 +7852,7 @@ set_linkage_for_static_data_member (tree decl) If SCOPE is non-NULL, it is the class type or namespace containing the variable. If SCOPE is NULL, the variable should is created in - the innermost enclosings scope. */ + the innermost enclosing scope. */ static tree grokvardecl (tree type, @@ -7972,33 +7950,8 @@ grokvardecl (tree type, declare an entity with linkage. DR 757 relaxes this restriction for C++0x. */ - tree t = (cxx_dialect > cxx98 ? NULL_TREE - : no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)); - if (t) - { - if (TYPE_ANONYMOUS_P (t)) - { - if (DECL_EXTERN_C_P (decl)) - /* Allow this; it's pretty common in C. */ - ; - else - { - /* DRs 132, 319 and 389 seem to indicate types with - no linkage can only be used to declare extern "C" - entities. Since it's not always an error in the - ISO C++ 90 Standard, we only issue a warning. */ - warning (0, "anonymous type with no linkage used to declare " - "variable %q#D with linkage", decl); - if (DECL_ORIGINAL_TYPE (TYPE_NAME (t))) - warning (0, "%q+#D does not refer to the unqualified " - "type, so it is not used for linkage", - TYPE_NAME (t)); - } - } - else - warning (0, "type %qT with no linkage used to declare variable " - "%q#D with linkage", t, decl); - } + if (cxx_dialect < cxx11) + no_linkage_error (decl); } else DECL_INTERFACE_KNOWN (decl) = 1; @@ -8670,23 +8623,6 @@ check_var_type (tree identifier, tree type) return type; } -/* Functions for adjusting the visibility of a tagged type and its nested - types when it gets a name for linkage purposes from a typedef. */ - -static void bt_reset_linkage (binding_entry, void *); -static void -reset_type_linkage (tree type) -{ - set_linkage_according_to_type (type, TYPE_MAIN_DECL (type)); - if (CLASS_TYPE_P (type)) - binding_table_foreach (CLASSTYPE_NESTED_UTDS (type), bt_reset_linkage, NULL); -} -static void -bt_reset_linkage (binding_entry b, void */*data*/) -{ - reset_type_linkage (b->type); -} - /* Given declspecs and a declarator (abstract or otherwise), determine the name and type of the object declared and construct a DECL node for it. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index f5125417c6d..1afe16ee949 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2475,6 +2475,125 @@ constrain_class_visibility (tree type) } } +/* Functions for adjusting the visibility of a tagged type and its nested + types and declarations when it gets a name for linkage purposes from a + typedef. */ + +static void bt_reset_linkage_1 (binding_entry, void *); +static void bt_reset_linkage_2 (binding_entry, void *); + +/* First reset the visibility of all the types. */ + +static void +reset_type_linkage_1 (tree type) +{ + set_linkage_according_to_type (type, TYPE_MAIN_DECL (type)); + if (CLASS_TYPE_P (type)) + binding_table_foreach (CLASSTYPE_NESTED_UTDS (type), + bt_reset_linkage_1, NULL); +} +static void +bt_reset_linkage_1 (binding_entry b, void */*data*/) +{ + reset_type_linkage_1 (b->type); +} + +/* Then reset the visibility of any static data members or member + functions that use those types. */ + +static void +reset_decl_linkage (tree decl) +{ + if (TREE_PUBLIC (decl)) + return; + if (DECL_CLONED_FUNCTION_P (decl)) + return; + TREE_PUBLIC (decl) = true; + DECL_INTERFACE_KNOWN (decl) = false; + determine_visibility (decl); + tentative_decl_linkage (decl); +} +static void +reset_type_linkage_2 (tree type) +{ + if (CLASS_TYPE_P (type)) + { + if (tree vt = CLASSTYPE_VTABLES (type)) + { + tree name = mangle_vtbl_for_type (type); + DECL_NAME (vt) = name; + SET_DECL_ASSEMBLER_NAME (vt, name); + reset_decl_linkage (vt); + } + if (tree ti = CLASSTYPE_TYPEINFO_VAR (type)) + { + tree name = mangle_typeinfo_for_type (type); + DECL_NAME (ti) = name; + SET_DECL_ASSEMBLER_NAME (ti, name); + TREE_TYPE (name) = type; + reset_decl_linkage (ti); + } + for (tree m = TYPE_FIELDS (type); m; m = DECL_CHAIN (m)) + if (TREE_CODE (m) == VAR_DECL) + reset_decl_linkage (m); + for (tree m = TYPE_METHODS (type); m; m = DECL_CHAIN (m)) + reset_decl_linkage (m); + binding_table_foreach (CLASSTYPE_NESTED_UTDS (type), + bt_reset_linkage_2, NULL); + } +} +static void +bt_reset_linkage_2 (binding_entry b, void */*data*/) +{ + reset_type_linkage_2 (b->type); +} +void +reset_type_linkage (tree type) +{ + reset_type_linkage_1 (type); + reset_type_linkage_2 (type); +} + +/* Set up our initial idea of what the linkage of DECL should be. */ + +void +tentative_decl_linkage (tree decl) +{ + if (DECL_INTERFACE_KNOWN (decl)) + /* We've already made a decision as to how this function will + be handled. */; + else if (vague_linkage_p (decl)) + { + if (TREE_CODE (decl) == FUNCTION_DECL) + { + DECL_EXTERNAL (decl) = 1; + DECL_NOT_REALLY_EXTERN (decl) = 1; + note_vague_linkage_fn (decl); + /* A non-template inline function with external linkage will + always be COMDAT. As we must eventually determine the + linkage of all functions, and as that causes writes to + the data mapped in from the PCH file, it's advantageous + to mark the functions at this point. */ + if (DECL_DECLARED_INLINE_P (decl) + && (!DECL_IMPLICIT_INSTANTIATION (decl) + || DECL_DEFAULTED_FN (decl))) + { + /* This function must have external linkage, as + otherwise DECL_INTERFACE_KNOWN would have been + set. */ + gcc_assert (TREE_PUBLIC (decl)); + comdat_linkage (decl); + DECL_INTERFACE_KNOWN (decl) = 1; + } + } + else + { + gcc_assert (TREE_CODE (decl) == VAR_DECL); + maybe_commonize_var (decl); + } + } +} + /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage for DECL has not already been determined, do so now by setting DECL_EXTERNAL, DECL_COMDAT and other related flags. Until this @@ -3966,23 +4085,57 @@ decl_maybe_constant_var_p (tree decl) && INTEGRAL_OR_ENUMERATION_TYPE_P (type)); } -/* Complain that DECL uses a type with no linkage but is never defined. */ +/* Complain that DECL uses a type with no linkage. In C++98 mode this is + called from grokfndecl and grokvardecl; in all modes it is called from + cp_write_global_declarations. */ -static void +void no_linkage_error (tree decl) { + if (cxx_dialect >= cxx11 && decl_defined_p (decl)) + /* In C++11 it's ok if the decl is defined. */ + return; tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false); - if (TYPE_ANONYMOUS_P (t)) + if (t == NULL_TREE) + /* The type that got us on no_linkage_decls must have gotten a name for + linkage purposes. */; + else if (CLASS_TYPE_P (t) && TYPE_BEING_DEFINED (t)) + /* The type might end up having a typedef name for linkage purposes. */ + vec_safe_push (no_linkage_decls, decl); + else if (TYPE_ANONYMOUS_P (t)) { - permerror (0, "%q+#D, declared using anonymous type, " - "is used but never defined", decl); - if (is_typedef_decl (TYPE_NAME (t))) - permerror (0, "%q+#D does not refer to the unqualified type, " - "so it is not used for linkage", TYPE_NAME (t)); + bool d = false; + if (cxx_dialect >= cxx11) + d = permerror (DECL_SOURCE_LOCATION (decl), "%q#D, declared using " + "anonymous type, is used but never defined", decl); + else if (DECL_EXTERN_C_P (decl)) + /* Allow this; it's pretty common in C. */; + else if (TREE_CODE (decl) == VAR_DECL) + /* DRs 132, 319 and 389 seem to indicate types with + no linkage can only be used to declare extern "C" + entities. Since it's not always an error in the + ISO C++ 90 Standard, we only issue a warning. */ + d = warning_at (DECL_SOURCE_LOCATION (decl), 0, "anonymous type " + "with no linkage used to declare variable %q#D with " + "linkage", decl); + else + d = permerror (DECL_SOURCE_LOCATION (decl), "anonymous type with no " + "linkage used to declare function %q#D with linkage", + decl); + if (d && is_typedef_decl (TYPE_NAME (t))) + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), "%q#D does not refer " + "to the unqualified type, so it is not used for linkage", + TYPE_NAME (t)); } + else if (cxx_dialect >= cxx11) + permerror (DECL_SOURCE_LOCATION (decl), "%q#D, declared using local type " + "%qT, is used but never defined", decl, t); + else if (TREE_CODE (decl) == VAR_DECL) + warning_at (DECL_SOURCE_LOCATION (decl), 0, "type %qT with no linkage " + "used to declare variable %q#D with linkage", t, decl); else - permerror (0, "%q+#D, declared using local type %qT, " - "is used but never defined", decl, t); + permerror (DECL_SOURCE_LOCATION (decl), "type %qT with no linkage used " + "to declare function %q#D with linkage", t, decl); } /* Collect declarations from all namespaces relevant to SOURCE_FILE. */ @@ -4407,8 +4560,7 @@ cp_write_global_declarations (void) /* So must decls that use a type with no linkage. */ FOR_EACH_VEC_SAFE_ELT (no_linkage_decls, i, decl) - if (!decl_defined_p (decl)) - no_linkage_error (decl); + no_linkage_error (decl); /* Then, do the Objective-C stuff. This is where all the Objective-C module stuff gets generated (symtab, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 85d6807cd2e..9c1c29d28e4 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3977,25 +3977,7 @@ expand_or_defer_fn_1 (tree fn) /* We've already made a decision as to how this function will be handled. */; else if (!at_eof) - { - DECL_EXTERNAL (fn) = 1; - DECL_NOT_REALLY_EXTERN (fn) = 1; - note_vague_linkage_fn (fn); - /* A non-template inline function with external linkage will - always be COMDAT. As we must eventually determine the - linkage of all functions, and as that causes writes to - the data mapped in from the PCH file, it's advantageous - to mark the functions at this point. */ - if (!DECL_IMPLICIT_INSTANTIATION (fn) || DECL_DEFAULTED_FN (fn)) - { - /* This function must have external linkage, as - otherwise DECL_INTERFACE_KNOWN would have been - set. */ - gcc_assert (TREE_PUBLIC (fn)); - comdat_linkage (fn); - DECL_INTERFACE_KNOWN (fn) = 1; - } - } + tentative_decl_linkage (fn); else import_export_decl (fn); diff --git a/gcc/testsuite/g++.dg/abi/anon2.C b/gcc/testsuite/g++.dg/abi/anon2.C new file mode 100644 index 00000000000..a818b70e5a9 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/anon2.C @@ -0,0 +1,66 @@ +// PR c++/55877 +// { dg-require-weak "" } + +namespace N1 { + typedef struct { + typedef enum { X, Y } A; + typedef struct { } B; + struct C { + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZN2N11D1C3fn1ENS0_1BE" } } + static void fn1 (B) { } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZN2N11D1C3fn2ES1_" } } + static void fn2 (C) { } + }; + } D; + + void *p = (void *) D::C::fn1; + void *q = (void *) D::C::fn2; +} + +namespace N2 { + typedef struct { + typedef enum { X, Y } A; + typedef struct { } B; + struct C { + // { dg-final { scan-assembler-not ".weak\(_definition\)?\[ \t\]_?_ZN2N23._31C3fn1ENS0_1BE" } } + static void fn1 (B) { } // { dg-error "no linkage" "" { target c++98 } } + // { dg-final { scan-assembler-not ".weak\(_definition\)?\[ \t\]_?_ZN2N23._31C3fn2ES1_" } } + static void fn2 (C) { } // { dg-error "no linkage" "" { target c++98 } } + }; + } const D; + + void *p = (void *) D::C::fn1; + void *q = (void *) D::C::fn2; +} + +namespace N3 { + typedef struct { + typedef enum { X, Y } A; + typedef struct { } B; + template struct C { + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZN2N31D1CIiE3fn1ENS0_1BE" } } + static void fn1 (B) { } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZN2N31D1CIiE3fn2ES2_" } } + static void fn2 (C) { } + }; + } D; + + void *p = (void *) D::C::fn1; + void *q = (void *) D::C::fn2; +} + +namespace N4 { + typedef struct { + typedef enum { X, Y } A; + typedef struct { } B; + template struct C { + // { dg-final { scan-assembler-not ".weak\(_definition\)?\[ \t\]_?_ZN2N43._91CIiE3fn1ENS0_1BE" } } + static void fn1 (B) { } // { not-dg-error "no linkage" "" { target c++98 } } + // { dg-final { scan-assembler-not ".weak\(_definition\)?\[ \t\]_?_ZN2N43._91CIiE3fn2ES2_" } } + static void fn2 (C) { } // { not-dg-error "no linkage" "" { target c++98 } } + }; + } const D; + + void *p = (void *) D::C::fn1; + void *q = (void *) D::C::fn2; +} diff --git a/gcc/testsuite/g++.dg/abi/anon3.C b/gcc/testsuite/g++.dg/abi/anon3.C new file mode 100644 index 00000000000..623c7f5c6e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/anon3.C @@ -0,0 +1,19 @@ +// { dg-require-weak "" } + +typedef struct { + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZN4Heya4blahEv" } } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZTI4Heya" } } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZTV4Heya" } } + virtual const char *blah() { + return "Heya::blah"; + } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZN4Heya1A1fEv" } } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZTIN4Heya1AE" } } + // { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZTVN4Heya1AE" } } + struct A { + virtual void f() { } + }; +} Heya; + +Heya h; +Heya::A a; diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/linkage1.C b/gcc/testsuite/g++.old-deja/g++.oliva/linkage1.C index 23295ea363d..6c4874b2138 100644 --- a/gcc/testsuite/g++.old-deja/g++.oliva/linkage1.C +++ b/gcc/testsuite/g++.old-deja/g++.oliva/linkage1.C @@ -11,8 +11,6 @@ // checking that another translation unit can call it. We don't do // the right things on functions, but we do on data members. -// { dg-bogus "" "" { xfail *-*-* } 0 } - typedef struct { void f(); } S; diff --git a/gcc/testsuite/g++.old-deja/g++.other/anon9.C b/gcc/testsuite/g++.old-deja/g++.other/anon9.C index d458b6b4309..acb4f460608 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/anon9.C +++ b/gcc/testsuite/g++.old-deja/g++.other/anon9.C @@ -2,5 +2,5 @@ // Test that we properly diagnose an attempt to use an anonymous class // in declaring an external function. -typedef const struct { int i; } T; // { dg-error "" } referenced below +typedef const struct { int i; } T; // { dg-message "" } referenced below void f (T* t); // { dg-error "" } uses unnamed type