From 1eee69dd7102f777d5a147beb7d7686a7057df78 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 2 Nov 2009 11:14:26 -0500 Subject: [PATCH] Restrict DR 757 change to C++0x mode. * decl2.c (mark_used): Check cxx_dialect. * decl.c (grokfndecl): Do check type linkage in C++98 mode. (grokvardecl): Likewise. * pt.c (check_instantiated_arg): Likewise. From-SVN: r153816 --- gcc/cp/ChangeLog | 8 ++ gcc/cp/decl.c | 77 +++++++++++++++++-- gcc/cp/decl2.c | 3 +- gcc/cp/pt.c | 30 +++++++- gcc/testsuite/ChangeLog | 18 +++++ gcc/testsuite/g++.dg/abi/mangle32.C | 3 + .../g++.dg/{other => cpp0x}/linkage2.C | 2 + gcc/testsuite/g++.dg/cpp0x/nolinkage1.C | 1 + gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C | 2 +- gcc/testsuite/g++.dg/ext/anon-struct4.C | 1 + gcc/testsuite/g++.dg/lookup/anon2.C | 6 +- gcc/testsuite/g++.dg/other/anon3.C | 2 +- gcc/testsuite/g++.dg/template/arg2.C | 2 +- gcc/testsuite/g++.dg/template/local4.C | 2 +- .../g++.old-deja/g++.law/operators32.C | 4 +- gcc/testsuite/g++.old-deja/g++.other/anon9.C | 5 -- .../g++.old-deja/g++.other/linkage1.C | 13 ++-- .../g++.old-deja/g++.other/linkage2.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/enum6.C | 2 +- 19 files changed, 149 insertions(+), 34 deletions(-) rename gcc/testsuite/g++.dg/{other => cpp0x}/linkage2.C (97%) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 044b5689747..1921f7288b2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2009-11-02 Jason Merrill + + Restrict DR 757 change to C++0x mode. + * decl2.c (mark_used): Check cxx_dialect. + * decl.c (grokfndecl): Do check type linkage in C++98 mode. + (grokvardecl): Likewise. + * pt.c (check_instantiated_arg): Likewise. + 2009-11-02 Jakub Jelinek PR c++/41774 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 33023a7649c..de29d0bdb63 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6768,6 +6768,36 @@ grokfndecl (tree ctype, || decl_function_context (TYPE_MAIN_DECL (ctype)))) publicp = 0; + if (publicp && cxx_dialect == cxx98) + { + /* [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. + + 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, "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; if (! publicp) { @@ -7007,15 +7037,48 @@ grokvardecl (tree type, if (declspecs->specs[(int)ds_thread]) DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); + /* If the type of the decl has no linkage, make sure that we'll + notice that in mark_used. */ + if (cxx_dialect > cxx98 + && decl_linkage (decl) != lk_none + && DECL_LANG_SPECIFIC (decl) == NULL + && !DECL_EXTERN_C_P (decl) + && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) + retrofit_lang_decl (decl); + if (TREE_PUBLIC (decl)) { - /* If the type of the decl has no linkage, make sure that we'll - notice that in mark_used. */ - if (DECL_LANG_SPECIFIC (decl) == NULL - && TREE_PUBLIC (decl) - && !DECL_EXTERN_C_P (decl) - && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) - retrofit_lang_decl (decl); + /* [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. + + 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, "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 DECL_INTERFACE_KNOWN (decl) = 1; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 592ee086961..b1fe4b9e31c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3990,7 +3990,8 @@ mark_used (tree decl) 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 (decl_linkage (decl) != lk_none + if (cxx_dialect > cxx98 + && decl_linkage (decl) != lk_none && !DECL_EXTERN_C_P (decl) && !DECL_ARTIFICIAL (decl) && !decl_defined_p (decl) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9983a951aee..2f0fa125376 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12479,7 +12479,7 @@ tsubst_copy_and_build (tree t, } /* Verify that the instantiated ARGS are valid. For type arguments, - make sure that the type is not variably modified. For non-type arguments, + make sure that the type's linkage is ok. For non-type arguments, make sure they are constants if they are integral or enumerations. Emit an error under control of COMPLAIN, and return TRUE on error. */ @@ -12500,7 +12500,33 @@ check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain) } else if (TYPE_P (t)) { - if (variably_modified_type_p (t, NULL_TREE)) + /* [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. + This implies that names with no linkage cannot be used as + template arguments + + DR 757 relaxes this restriction for C++0x. */ + tree nt = (cxx_dialect > cxx98 ? NULL_TREE + : 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) error ("%qT is a variably modified type", t); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2d1378aa7a9..52a26bc9d4c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2009-11-02 Jason Merrill + + * g++.dg/other/linkage2.C: Move to... + * g++.dg/cpp0x/linkage2.C: ..here. + * g++.dg/abi/mangle32.C: Add -std=c++0x. + * g++.dg/cpp0x/nolinkage1.C: Likewise. + * g++.dg/debug/dwarf2/anonname1.C: Likewise. + * g++.dg/ext/anon-struct4.C: Revert earlier change. + * 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: Likewise. + * g++.old-deja/g++.other/linkage1.C: Likewise. + 2009-11-02 Ulrich Weigand PR tree-optimization/41857 diff --git a/gcc/testsuite/g++.dg/abi/mangle32.C b/gcc/testsuite/g++.dg/abi/mangle32.C index de02887f997..244d07490f8 100644 --- a/gcc/testsuite/g++.dg/abi/mangle32.C +++ b/gcc/testsuite/g++.dg/abi/mangle32.C @@ -2,6 +2,9 @@ // namespace-scope unnamed types have no linkage, so we only test that they // are distinct. + +// { dg-options -std=c++0x } + typedef struct { } *A; typedef struct { } *B; diff --git a/gcc/testsuite/g++.dg/other/linkage2.C b/gcc/testsuite/g++.dg/cpp0x/linkage2.C similarity index 97% rename from gcc/testsuite/g++.dg/other/linkage2.C rename to gcc/testsuite/g++.dg/cpp0x/linkage2.C index 4e3e6f1eab3..f41c21a7741 100644 --- a/gcc/testsuite/g++.dg/other/linkage2.C +++ b/gcc/testsuite/g++.dg/cpp0x/linkage2.C @@ -4,6 +4,8 @@ // o the variable or function is not used (3.2 [basic.def.odr]) or is // defined in the same translation unit. +// { dg-options -std=c++0x } + template struct B { void g(T){} void h(T); // { dg-error "never defined" } diff --git a/gcc/testsuite/g++.dg/cpp0x/nolinkage1.C b/gcc/testsuite/g++.dg/cpp0x/nolinkage1.C index a31394b08ac..b69b6ddc4cf 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nolinkage1.C +++ b/gcc/testsuite/g++.dg/cpp0x/nolinkage1.C @@ -3,6 +3,7 @@ // { dg-additional-sources "nolinkage1a.cc" } // { dg-do link } +// { dg-options -std=c++0x } #include "nolinkage1.h" diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C b/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C index dcd2d8d5660..c9da2d69866 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C @@ -1,6 +1,6 @@ // PR debug/41828 // { dg-do compile } -// { dg-options "-gdwarf-2 -dA" } +// { dg-options "-gdwarf-2 -dA -std=c++0x" } // { dg-final { scan-assembler-not " class X {}; void fn () { class L {}; - X f; + X f; // { dg-error "uses local type|trying to instantiate|no type|invalid type" "" } } diff --git a/gcc/testsuite/g++.dg/template/local4.C b/gcc/testsuite/g++.dg/template/local4.C index 41e2370c395..cfa37364975 100644 --- a/gcc/testsuite/g++.dg/template/local4.C +++ b/gcc/testsuite/g++.dg/template/local4.C @@ -4,5 +4,5 @@ template void foo() {} int main () { struct S {}; - foo (); + foo (); // { dg-error "match" } } diff --git a/gcc/testsuite/g++.old-deja/g++.law/operators32.C b/gcc/testsuite/g++.old-deja/g++.law/operators32.C index 89f0b6601aa..91de03ee8fc 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/operators32.C +++ b/gcc/testsuite/g++.old-deja/g++.law/operators32.C @@ -49,7 +49,7 @@ foo() {std::cout << "foo created" << std::endl; } }; foo **f2; -allocate2d(d1, d2, f2); -ffree(d1, f2); +allocate2d(d1, d2, f2);// { dg-error "" } type.*// ERROR - trying to.* +ffree(d1, f2);// { dg-error "" } type.*// ERROR - trying to.* } diff --git a/gcc/testsuite/g++.old-deja/g++.other/anon9.C b/gcc/testsuite/g++.old-deja/g++.other/anon9.C index f4b192337c1..a364db8e962 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/anon9.C +++ b/gcc/testsuite/g++.old-deja/g++.other/anon9.C @@ -4,8 +4,3 @@ typedef const struct { int i; } T; // { dg-error "" } referenced below void f (T* t); // { dg-error "" } uses unnamed type - -int main() -{ - f(0); -} diff --git a/gcc/testsuite/g++.old-deja/g++.other/linkage1.C b/gcc/testsuite/g++.old-deja/g++.other/linkage1.C index de9a6accf18..e9b5a9d2aa3 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/linkage1.C +++ b/gcc/testsuite/g++.old-deja/g++.other/linkage1.C @@ -3,16 +3,13 @@ typedef struct { int i; } *p; -void f (p) { } -p q; +void f (p) { } // { dg-error "uses anonymous type" } +p q; // { dg-warning "uses anonymous type" } int main() { - extern p j; // { dg-error "anonymous type" } - j+1; + extern p j; // { dg-warning "uses anonymous type" } struct A { int j; }; - extern A a; // { dg-error "local type" } - a.j+1; - extern void f (A); // { dg-error "local type" } - f(a); + extern A a; // { dg-warning "uses local type" } + extern void f (A); // { dg-error "uses local type" } } diff --git a/gcc/testsuite/g++.old-deja/g++.other/linkage2.C b/gcc/testsuite/g++.old-deja/g++.other/linkage2.C index 64f74f7292c..2385b2216fe 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/linkage2.C +++ b/gcc/testsuite/g++.old-deja/g++.other/linkage2.C @@ -7,7 +7,7 @@ extern GDBM_FILE gdbm_open(); } typedef struct { int dummy[10]; } *FAIL_FILE; -extern FAIL_FILE fail_open(); // OK because it's never used +extern FAIL_FILE fail_open(); // { dg-error "" } non-local function typedef struct { int dummy[10]; } *SUCCESS_FILE, S; extern SUCCESS_FILE success_open(); diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum6.C b/gcc/testsuite/g++.old-deja/g++.pt/enum6.C index 561254d0d68..254b48bc7fc 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/enum6.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/enum6.C @@ -8,7 +8,7 @@ void fn(T) { enum tern { H, L, X, U }; - vector ternvec; + vector ternvec; // { dg-error "" } composed from a local type } template void fn(int);