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.
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);
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;
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,
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;
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.
}
}
+/* 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
&& 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. */
/* 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,
/* 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);
--- /dev/null
+// 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;
+}
--- /dev/null
+// { 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;
// 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;
// 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