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
This commit is contained in:
parent
a6659b552d
commit
944b63dbc0
|
@ -1,5 +1,17 @@
|
||||||
2014-02-25 Jason Merrill <jason@redhat.com>
|
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
|
* decl2.c (finish_static_data_member_decl): Diagnose static data
|
||||||
member in unnamed class.
|
member in unnamed class.
|
||||||
* class.c (finish_struct_anon_r): Avoid redundant diagnostic.
|
* class.c (finish_struct_anon_r): Avoid redundant diagnostic.
|
||||||
|
|
|
@ -5313,12 +5313,15 @@ extern tree coerce_delete_type (tree);
|
||||||
extern void comdat_linkage (tree);
|
extern void comdat_linkage (tree);
|
||||||
extern void determine_visibility (tree);
|
extern void determine_visibility (tree);
|
||||||
extern void constrain_class_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 void import_export_decl (tree);
|
||||||
extern tree build_cleanup (tree);
|
extern tree build_cleanup (tree);
|
||||||
extern tree build_offset_ref_call_from_tree (tree, vec<tree, va_gc> **,
|
extern tree build_offset_ref_call_from_tree (tree, vec<tree, va_gc> **,
|
||||||
tsubst_flags_t);
|
tsubst_flags_t);
|
||||||
extern bool decl_constant_var_p (tree);
|
extern bool decl_constant_var_p (tree);
|
||||||
extern bool decl_maybe_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 void check_default_args (tree);
|
||||||
extern bool mark_used (tree);
|
extern bool mark_used (tree);
|
||||||
extern bool mark_used (tree, tsubst_flags_t);
|
extern bool mark_used (tree, tsubst_flags_t);
|
||||||
|
|
|
@ -7569,29 +7569,7 @@ grokfndecl (tree ctype,
|
||||||
declare an entity with linkage.
|
declare an entity with linkage.
|
||||||
|
|
||||||
DR 757 relaxes this restriction for C++0x. */
|
DR 757 relaxes this restriction for C++0x. */
|
||||||
t = no_linkage_check (TREE_TYPE (decl),
|
no_linkage_error (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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TREE_PUBLIC (decl) = publicp;
|
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
|
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 variable. If SCOPE is NULL, the variable should is created in
|
||||||
the innermost enclosings scope. */
|
the innermost enclosing scope. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
grokvardecl (tree type,
|
grokvardecl (tree type,
|
||||||
|
@ -7972,33 +7950,8 @@ grokvardecl (tree type,
|
||||||
declare an entity with linkage.
|
declare an entity with linkage.
|
||||||
|
|
||||||
DR 757 relaxes this restriction for C++0x. */
|
DR 757 relaxes this restriction for C++0x. */
|
||||||
tree t = (cxx_dialect > cxx98 ? NULL_TREE
|
if (cxx_dialect < cxx11)
|
||||||
: no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false));
|
no_linkage_error (decl);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DECL_INTERFACE_KNOWN (decl) = 1;
|
DECL_INTERFACE_KNOWN (decl) = 1;
|
||||||
|
@ -8670,23 +8623,6 @@ check_var_type (tree identifier, tree type)
|
||||||
return 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
|
/* Given declspecs and a declarator (abstract or otherwise), determine
|
||||||
the name and type of the object declared and construct a DECL node
|
the name and type of the object declared and construct a DECL node
|
||||||
for it.
|
for it.
|
||||||
|
|
176
gcc/cp/decl2.c
176
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
|
/* 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
|
for DECL has not already been determined, do so now by setting
|
||||||
DECL_EXTERNAL, DECL_COMDAT and other related flags. Until this
|
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));
|
&& 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)
|
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);
|
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, "
|
bool d = false;
|
||||||
"is used but never defined", decl);
|
if (cxx_dialect >= cxx11)
|
||||||
if (is_typedef_decl (TYPE_NAME (t)))
|
d = permerror (DECL_SOURCE_LOCATION (decl), "%q#D, declared using "
|
||||||
permerror (0, "%q+#D does not refer to the unqualified type, "
|
"anonymous type, is used but never defined", decl);
|
||||||
"so it is not used for linkage", TYPE_NAME (t));
|
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
|
else
|
||||||
permerror (0, "%q+#D, declared using local type %qT, "
|
permerror (DECL_SOURCE_LOCATION (decl), "type %qT with no linkage used "
|
||||||
"is used but never defined", decl, t);
|
"to declare function %q#D with linkage", t, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Collect declarations from all namespaces relevant to SOURCE_FILE. */
|
/* 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. */
|
/* So must decls that use a type with no linkage. */
|
||||||
FOR_EACH_VEC_SAFE_ELT (no_linkage_decls, i, decl)
|
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
|
/* Then, do the Objective-C stuff. This is where all the
|
||||||
Objective-C module stuff gets generated (symtab,
|
Objective-C module stuff gets generated (symtab,
|
||||||
|
|
|
@ -3977,25 +3977,7 @@ expand_or_defer_fn_1 (tree fn)
|
||||||
/* We've already made a decision as to how this function will
|
/* We've already made a decision as to how this function will
|
||||||
be handled. */;
|
be handled. */;
|
||||||
else if (!at_eof)
|
else if (!at_eof)
|
||||||
{
|
tentative_decl_linkage (fn);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
import_export_decl (fn);
|
import_export_decl (fn);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
|
@ -11,8 +11,6 @@
|
||||||
// checking that another translation unit can call it. We don't do
|
// checking that another translation unit can call it. We don't do
|
||||||
// the right things on functions, but we do on data members.
|
// the right things on functions, but we do on data members.
|
||||||
|
|
||||||
// { dg-bogus "" "" { xfail *-*-* } 0 }
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void f();
|
void f();
|
||||||
} S;
|
} S;
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
// Test that we properly diagnose an attempt to use an anonymous class
|
// Test that we properly diagnose an attempt to use an anonymous class
|
||||||
// in declaring an external function.
|
// 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
|
void f (T* t); // { dg-error "" } uses unnamed type
|
||||||
|
|
Loading…
Reference in New Issue