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:
Jason Merrill 2014-02-25 16:19:06 -05:00 committed by Jason Merrill
parent a6659b552d
commit 944b63dbc0
9 changed files with 270 additions and 102 deletions

View 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.

View 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);

View 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.

View 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))
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,

View 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);

View File

@ -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;
}

View File

@ -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;

View 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;

View 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