Implement DR 757...

Implement DR 757: It's OK for a decl to use a type without linkage
	so long as the decl is defined in the current translation unit.
	* decl2.c (no_linkage_decls): New vector.
	(mark_used): Add decls that use types with no linkage.
	(cp_write_global_declarations): Check that they are defined.
	(decl_defined_p, no_linkage_error): New fns.
	* cp-tree.h (DECL_NO_LINKAGE_CHECKED): New macro.
	(struct lang_decl_base): Add flag.
	* decl.c (grokfndecl): Don't check type linkage.
	(grokvardecl): If the type has no linkage, just make sure
	DECL_LANG_SPECIFIC is set.
	* pt.c (check_instantiated_arg): Don't check type linkage.
	* name-lookup.c (is_local_extern): New fn.
	* name-lookup.h: Declare it.

From-SVN: r150634
This commit is contained in:
Jason Merrill 2009-08-10 16:47:55 -04:00 committed by Jason Merrill
parent 8d1b99e26a
commit e8f43da6f9
19 changed files with 204 additions and 102 deletions

View File

@ -1,3 +1,20 @@
2009-08-10 Jason Merrill <jason@redhat.com>
Implement DR 757: It's OK for a decl to use a type without linkage
so long as the decl is defined in the current translation unit.
* decl2.c (no_linkage_decls): New vector.
(mark_used): Add decls that use types with no linkage.
(cp_write_global_declarations): Check that they are defined.
(decl_defined_p, no_linkage_error): New fns.
* cp-tree.h (DECL_NO_LINKAGE_CHECKED): New macro.
(struct lang_decl_base): Add flag.
* decl.c (grokfndecl): Don't check type linkage.
(grokvardecl): If the type has no linkage, just make sure
DECL_LANG_SPECIFIC is set.
* pt.c (check_instantiated_arg): Don't check type linkage.
* name-lookup.c (is_local_extern): New fn.
* name-lookup.h: Declare it.
2009-08-05 Jason Merrill <jason@redhat.com> 2009-08-05 Jason Merrill <jason@redhat.com>
PR c++/40948 PR c++/40948

View File

@ -1579,8 +1579,9 @@ struct GTY(()) lang_decl_base {
unsigned anticipated_p : 1; /* fn or type */ unsigned anticipated_p : 1; /* fn or type */
unsigned friend_attr : 1; /* fn or type */ unsigned friend_attr : 1; /* fn or type */
unsigned template_conv_p : 1; /* template only? */ unsigned template_conv_p : 1; /* template only? */
unsigned no_linkage_checked : 1; /* var or fn */
unsigned u2sel : 1; unsigned u2sel : 1;
/* 2 spare bits */ /* 1 spare bit */
}; };
/* True for DECL codes which have template info and access. */ /* True for DECL codes which have template info and access. */
@ -1982,6 +1983,14 @@ struct GTY(()) lang_decl {
(DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \ (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \
->u.base.initialized_in_class) ->u.base.initialized_in_class)
/* Nonzero if we've checked whether DECL uses types without linkage in a
potentially invalid way.
??? Instead, should fix mark_used to only set TREE_USED when we're
really using something, and just return if it's already set. */
#define DECL_NO_LINKAGE_CHECKED(DECL) \
(DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \
->u.base.no_linkage_checked)
/* Nonzero for DECL means that this decl is just a friend declaration, /* Nonzero for DECL means that this decl is just a friend declaration,
and should not be added to the list of members for this class. */ and should not be added to the list of members for this class. */
#define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC (NODE)->u.base.friend_attr) #define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC (NODE)->u.base.friend_attr)

View File

@ -6747,36 +6747,6 @@ grokfndecl (tree ctype,
|| decl_function_context (TYPE_MAIN_DECL (ctype)))) || decl_function_context (TYPE_MAIN_DECL (ctype))))
publicp = 0; publicp = 0;
if (publicp)
{
/* [basic.link]: A name with no linkage (notably, the name of a class
or enumeration declared in a local scope) shall not be used to
declare an entity with linkage.
Only check this for public decls for now. See core 319, 389. */
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, "non-local function %q#D uses anonymous type",
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, "non-local function %q#D uses local type %qT", decl, t);
}
}
TREE_PUBLIC (decl) = publicp; TREE_PUBLIC (decl) = publicp;
if (! publicp) if (! publicp)
{ {
@ -7021,36 +6991,13 @@ grokvardecl (tree type,
if (TREE_PUBLIC (decl)) if (TREE_PUBLIC (decl))
{ {
/* [basic.link]: A name with no linkage (notably, the name of a class /* If the type of the decl has no linkage, make sure that we'll
or enumeration declared in a local scope) shall not be used to notice that in mark_used. */
declare an entity with linkage. if (DECL_LANG_SPECIFIC (decl) == NULL
&& TREE_PUBLIC (decl)
Only check this for public decls for now. */ && !DECL_EXTERN_C_P (decl)
tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false); && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false))
if (t) retrofit_lang_decl (decl);
{
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, "non-local variable %q#D uses anonymous type",
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, "non-local variable %q#D uses local type %qT", decl, t);
}
} }
else else
DECL_INTERFACE_KNOWN (decl) = 1; DECL_INTERFACE_KNOWN (decl) = 1;

View File

@ -84,6 +84,7 @@ static void write_out_vars (tree);
static void import_export_class (tree); static void import_export_class (tree);
static tree get_guard_bits (tree); static tree get_guard_bits (tree);
static void determine_visibility_from_class (tree, tree); static void determine_visibility_from_class (tree, tree);
static bool decl_defined_p (tree);
/* A list of static class variables. This is needed, because a /* A list of static class variables. This is needed, because a
static class variable can be declared inside the class without static class variable can be declared inside the class without
@ -94,6 +95,10 @@ static GTY(()) VEC(tree,gc) *pending_statics;
may need to emit outline anyway. */ may need to emit outline anyway. */
static GTY(()) VEC(tree,gc) *deferred_fns; static GTY(()) VEC(tree,gc) *deferred_fns;
/* A list of decls that use types with no linkage, which we need to make
sure are defined. */
static GTY(()) VEC(tree,gc) *no_linkage_decls;
/* Nonzero if we're done parsing and into end-of-file activities. */ /* Nonzero if we're done parsing and into end-of-file activities. */
int at_eof; int at_eof;
@ -3332,6 +3337,40 @@ build_java_method_aliases (void)
} }
} }
/* Returns true iff there is a definition available for variable or
function DECL. */
static bool
decl_defined_p (tree decl)
{
if (TREE_CODE (decl) == FUNCTION_DECL)
return (DECL_INITIAL (decl) != NULL_TREE);
else
{
gcc_assert (TREE_CODE (decl) == VAR_DECL);
return !DECL_EXTERNAL (decl);
}
}
/* Complain that DECL uses a type with no linkage but is never defined. */
static void
no_linkage_error (tree decl)
{
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));
}
else
permerror (0, "%q+#D, declared using local type %qT, "
"is used but never defined", decl, t);
}
/* This routine is called at the end of compilation. /* This routine is called at the end of compilation.
Its job is to create all the code needed to initialize and Its job is to create all the code needed to initialize and
destroy the global aggregates. We do the destruction destroy the global aggregates. We do the destruction
@ -3613,6 +3652,11 @@ cp_write_global_declarations (void)
} }
} }
/* So must decls that use a type with no linkage. */
for (i = 0; VEC_iterate (tree, no_linkage_decls, i, decl); ++i)
if (!decl_defined_p (decl))
no_linkage_error (decl);
/* We give C linkage to static constructors and destructors. */ /* We give C linkage to static constructors and destructors. */
push_lang_context (lang_name_c); push_lang_context (lang_name_c);
@ -3851,6 +3895,32 @@ mark_used (tree decl)
if (processing_template_decl) if (processing_template_decl)
return; return;
/* DR 757: A type without linkage shall not be used as the type of a
variable or function with linkage, unless
o the variable or function has extern "C" linkage (7.5 [dcl.link]), or
o the variable or function is not used (3.2 [basic.def.odr]) or is
defined in the same translation unit. */
if (TREE_PUBLIC (decl)
&& (TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& DECL_LANG_SPECIFIC (decl)
&& !DECL_NO_LINKAGE_CHECKED (decl))
{
DECL_NO_LINKAGE_CHECKED (decl) = true;
if (!DECL_EXTERN_C_P (decl)
&& !DECL_ARTIFICIAL (decl)
&& !decl_defined_p (decl)
&& no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false))
{
if (is_local_extern (decl))
/* There's no way to define a local extern, and adding it to
the vector interferes with GC, so give an error now. */
no_linkage_error (decl);
else
VEC_safe_push (tree, gc, no_linkage_decls, decl);
}
}
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
&& !TREE_ASM_WRITTEN (decl)) && !TREE_ASM_WRITTEN (decl))
/* Remember it, so we can check it was defined. */ /* Remember it, so we can check it was defined. */

View File

@ -4392,6 +4392,34 @@ lookup_name_innermost_nonclass_level (tree name)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
} }
/* Returns true iff DECL is a block-scope extern declaration of a function
or variable. */
bool
is_local_extern (tree decl)
{
cxx_binding *binding;
/* For functions, this is easy. */
if (TREE_CODE (decl) == FUNCTION_DECL)
return DECL_LOCAL_FUNCTION_P (decl);
if (TREE_CODE (decl) != VAR_DECL)
return false;
if (!current_function_decl)
return false;
/* For variables, this is not easy. We need to look at the binding stack
for the identifier to see whether the decl we have is a local. */
for (binding = IDENTIFIER_BINDING (DECL_NAME (decl));
binding && binding->scope->kind != sk_namespace;
binding = binding->previous)
if (binding->value == decl)
return LOCAL_BINDING_P (binding);
return false;
}
/* Like lookup_name_innermost_nonclass_level, but for types. */ /* Like lookup_name_innermost_nonclass_level, but for types. */
static tree static tree

View File

@ -318,6 +318,7 @@ extern tree remove_hidden_names (tree);
extern tree lookup_qualified_name (tree, tree, bool, bool); extern tree lookup_qualified_name (tree, tree, bool, bool);
extern tree lookup_name_nonclass (tree); extern tree lookup_name_nonclass (tree);
extern tree lookup_name_innermost_nonclass_level (tree); extern tree lookup_name_innermost_nonclass_level (tree);
extern bool is_local_extern (tree);
extern tree lookup_function_nonclass (tree, VEC(tree,gc) *, bool); extern tree lookup_function_nonclass (tree, VEC(tree,gc) *, bool);
extern void push_local_binding (tree, tree, int); extern void push_local_binding (tree, tree, int);
extern bool pushdecl_class_level (tree); extern bool pushdecl_class_level (tree);

View File

@ -12215,7 +12215,7 @@ tsubst_copy_and_build (tree t,
} }
/* Verify that the instantiated ARGS are valid. For type arguments, /* Verify that the instantiated ARGS are valid. For type arguments,
make sure that the type's linkage is ok. For non-type arguments, make sure that the type is not variably modified. For non-type arguments,
make sure they are constants if they are integral or enumerations. make sure they are constants if they are integral or enumerations.
Emit an error under control of COMPLAIN, and return TRUE on error. */ Emit an error under control of COMPLAIN, and return TRUE on error. */
@ -12236,30 +12236,7 @@ check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain)
} }
else if (TYPE_P (t)) else if (TYPE_P (t))
{ {
/* [basic.link]: A name with no linkage (notably, the name if (variably_modified_type_p (t, NULL_TREE))
of a class or enumeration declared in a local scope)
shall not be used to declare an entity with linkage.
This implies that names with no linkage cannot be used as
template arguments. */
tree nt = no_linkage_check (t, /*relaxed_p=*/false);
if (nt)
{
/* DR 488 makes use of a type with no linkage cause
type deduction to fail. */
if (complain & tf_error)
{
if (TYPE_ANONYMOUS_P (nt))
error ("%qT is/uses anonymous type", t);
else
error ("template argument for %qD uses local type %qT",
tmpl, t);
}
return true;
}
/* In order to avoid all sorts of complications, we do not
allow variably-modified types as template arguments. */
else if (variably_modified_type_p (t, NULL_TREE))
{ {
if (complain & tf_error) if (complain & tf_error)
error ("%qT is a variably modified type", t); error ("%qT is a variably modified type", t);

View File

@ -1,3 +1,18 @@
2009-08-10 Jason Merrill <jason@redhat.com>
* g++.dg/other/linkage2.C: New test for types-without-linkage
handling.
* g++.dg/ext/anon-struct4.C: No error about anonymous type.
* g++.dg/lookup/anon2.C: Likewise.
* g++.dg/other/anon3.C: Likewise.
* g++.dg/template/arg2.C: Likewise.
* g++.dg/template/local4.C: Likewise.
* g++.old-deja/g++.law/operators32.C: Likewise.
* g++.old-deja/g++.other/linkage2.C: Likewise.
* g++.old-deja/g++.pt/enum6.C: Likewise.
* g++.old-deja/g++.other/anon9.C: Use the undefined decls.
* g++.old-deja/g++.other/linkage1.C: Likewise.
2009-08-10 Manuel López-Ibáñez <manu@gcc.gnu.org> 2009-08-10 Manuel López-Ibáñez <manu@gcc.gnu.org>
* gcc.dg/dg.exp: Test also c-c++-common dir. * gcc.dg/dg.exp: Test also c-c++-common dir.

View File

@ -1,4 +1,3 @@
// PR c++/14401 // PR c++/14401
struct { struct { int& i ; } bar ; } foo ; // { dg-error "uninitialized" "uninit" } struct { struct { int& i ; } bar ; } foo ; // { dg-error "uninitialized" "uninit" }
// { dg-warning "anonymous" "anon" { target *-*-* } 3 }

View File

@ -1,9 +1,9 @@
// { dg-do compile } // { dg-do compile }
// { dg-options "" } // { dg-options "" }
// Make sure we issue a diagnostic if a type with no linkage is used // Make sure we don't issue a diagnostic if a type with no linkage is used
// to declare a a variable that has linkage. // to declare a a variable that has linkage if that variable is defined.
struct { int i; } a; // { dg-warning "anonymous type" } struct { int i; } a;
void foo() { a.i; } void foo() { a.i; }

View File

@ -4,4 +4,4 @@
// { dg-do compile } // { dg-do compile }
enum { a = 3 } x; // { dg-warning "anonymous type" } enum { a = 3 } x;

View File

@ -0,0 +1,31 @@
// DR 743: A type without linkage shall not be used as the type of a
// variable or function with linkage, unless
// o the variable or function has extern "C" linkage (7.5 [dcl.link]), or
// o the variable or function is not used (3.2 [basic.def.odr]) or is
// defined in the same translation unit.
template <typename T> struct B {
void g(T){}
void h(T); // { dg-error "never defined" }
friend void i(B, T){}
static T t1; // { dg-error "never defined" }
static T t2;
};
template <typename T> T B<T>::t2 = { };
enum {} e1; // OK, defined
extern enum {} e2; // { dg-error "never defined" }
extern "C" enum {} e3; // OK, extern "C"
void f() {
struct A { int x; }; // no linkage
A a = {1};
B<A> ba; // declares B<A>::g(A) and B<A>::h(A)
ba.t1 = a; // error, B<T>::t never defined
ba.t2 = a; // OK
ba.g(a); // OK
ba.h(a); // error, B<T>::h never defined
i(ba, a); // OK
e1+e2+e3;
}

View File

@ -10,5 +10,5 @@ template <typename T> class X {};
void fn () void fn ()
{ {
class L {}; class L {};
X<L> f; // { dg-error "uses local type|trying to instantiate|no type|invalid type" "" } X<L> f;
} }

View File

@ -4,5 +4,5 @@ template <typename T> void foo() {}
int main () { int main () {
struct S {}; struct S {};
foo<S> (); // { dg-error "match" } foo<S> ();
} }

View File

@ -49,7 +49,7 @@ foo() {std::cout << "foo created" << std::endl; }
}; };
foo **f2; foo **f2;
allocate2d(d1, d2, f2);// { dg-error "" } type.*// ERROR - trying to.* allocate2d(d1, d2, f2);
ffree(d1, f2);// { dg-error "" } type.*// ERROR - trying to.* ffree(d1, f2);
} }

View File

@ -4,3 +4,8 @@
typedef const struct { int i; } T; // { dg-error "" } referenced below typedef const struct { int i; } T; // { dg-error "" } referenced below
void f (T* t); // { dg-error "" } uses unnamed type void f (T* t); // { dg-error "" } uses unnamed type
int main()
{
f(0);
}

View File

@ -3,13 +3,16 @@ typedef struct {
int i; int i;
} *p; } *p;
void f (p) { } // { dg-error "uses anonymous type" } void f (p) { }
p q; // { dg-warning "uses anonymous type" } p q;
int main() int main()
{ {
extern p j; // { dg-warning "uses anonymous type" } extern p j; // { dg-error "anonymous type" }
j+1;
struct A { int j; }; struct A { int j; };
extern A a; // { dg-warning "uses local type" } extern A a; // { dg-error "local type" }
extern void f (A); // { dg-error "uses local type" } a.j+1;
extern void f (A); // { dg-error "local type" }
f(a);
} }

View File

@ -7,7 +7,7 @@ extern GDBM_FILE gdbm_open();
} }
typedef struct { int dummy[10]; } *FAIL_FILE; typedef struct { int dummy[10]; } *FAIL_FILE;
extern FAIL_FILE fail_open(); // { dg-error "" } non-local function extern FAIL_FILE fail_open(); // OK because it's never used
typedef struct { int dummy[10]; } *SUCCESS_FILE, S; typedef struct { int dummy[10]; } *SUCCESS_FILE, S;
extern SUCCESS_FILE success_open(); extern SUCCESS_FILE success_open();

View File

@ -8,7 +8,7 @@ void fn(T)
{ {
enum tern { H, L, X, U }; enum tern { H, L, X, U };
vector<tern> ternvec; // { dg-error "" } composed from a local type vector<tern> ternvec;
} }
template void fn(int); template void fn(int);