re PR c++/55877 (Anon visibility issues)
authorJason Merrill <jason@redhat.com>
Tue, 25 Feb 2014 21:19:06 +0000 (16:19 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 25 Feb 2014 21:19:06 +0000 (16:19 -0500)
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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/abi/anon2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/abi/anon3.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.oliva/linkage1.C
gcc/testsuite/g++.old-deja/g++.other/anon9.C

index 9e3a63e..c4a8177 100644 (file)
@@ -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.
index 7681b27..3db18f3 100644 (file)
@@ -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);
index 04c4cf5..db86d97 100644 (file)
@@ -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.
index f512541..1afe16e 100644 (file)
@@ -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,
index 85d6807..9c1c29d 100644 (file)
@@ -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 (file)
index 0000000..a818b70
--- /dev/null
@@ -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 (file)
index 0000000..623c7f5
--- /dev/null
@@ -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;
index 23295ea..6c4874b 100644 (file)
@@ -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;
index d458b6b..acb4f46 100644 (file)
@@ -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