aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-02-25 16:19:06 -0500
committerJason Merrill <jason@gcc.gnu.org>2014-02-25 16:19:06 -0500
commit944b63dbc00d4866e40f5ee0b743b2c2f71c0fac (patch)
tree8e1328e1336c9af40c2714b3596faa9091015d87 /gcc
parenta6659b552d17639829425eef63e5a9569049f371 (diff)
downloadgcc-944b63dbc00d4866e40f5ee0b743b2c2f71c0fac.zip
gcc-944b63dbc00d4866e40f5ee0b743b2c2f71c0fac.tar.gz
gcc-944b63dbc00d4866e40f5ee0b743b2c2f71c0fac.tar.bz2
re PR c++/55877 (Anon visibility issues)
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. From-SVN: r208157
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog12
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl.c72
-rw-r--r--gcc/cp/decl2.c180
-rw-r--r--gcc/cp/semantics.c20
-rw-r--r--gcc/testsuite/g++.dg/abi/anon2.C66
-rw-r--r--gcc/testsuite/g++.dg/abi/anon3.C19
-rw-r--r--gcc/testsuite/g++.old-deja/g++.oliva/linkage1.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/anon9.C2
9 files changed, 272 insertions, 104 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9e3a63e..c4a8177 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,17 @@
2014-02-25 Jason Merrill <jason@redhat.com>
+ 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 7681b27..3db18f3 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<tree, va_gc> **,
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 04c4cf5..db86d97 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 f512541..1afe16e 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))
- {
- 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));
- }
+ 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))
+ {
+ 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 85d6807..9c1c29d 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 0000000..a818b70
--- /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 <class T> 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<int>::fn1;
+ void *q = (void *) D::C<int>::fn2;
+}
+
+namespace N4 {
+ typedef struct {
+ typedef enum { X, Y } A;
+ typedef struct { } B;
+ template <class T> 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<int>::fn1;
+ void *q = (void *) D::C<int>::fn2;
+}
diff --git a/gcc/testsuite/g++.dg/abi/anon3.C b/gcc/testsuite/g++.dg/abi/anon3.C
new file mode 100644
index 0000000..623c7f5
--- /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 23295ea..6c4874b 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 d458b6b..acb4f46 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