mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-24 08:50:26 +08:00
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>
|
||||
|
||||
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.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
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
|
||||
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,
|
||||
|
@ -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);
|
||||
|
||||
|
66
gcc/testsuite/g++.dg/abi/anon2.C
Normal file
66
gcc/testsuite/g++.dg/abi/anon2.C
Normal 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;
|
||||
}
|
19
gcc/testsuite/g++.dg/abi/anon3.C
Normal file
19
gcc/testsuite/g++.dg/abi/anon3.C
Normal 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;
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user