diff options
author | Jason Merrill <jason@redhat.com> | 2016-11-13 01:51:23 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2016-11-13 01:51:23 -0500 |
commit | ba1e69c03f96f8f9f0e0d4218b168bf975a83cbb (patch) | |
tree | 8ca33542913512e68c3e58353f1329b62dd1ae1e /gcc | |
parent | 478eca64649f582919bc67625e61d59b5c4eddef (diff) | |
download | gcc-ba1e69c03f96f8f9f0e0d4218b168bf975a83cbb.zip gcc-ba1e69c03f96f8f9f0e0d4218b168bf975a83cbb.tar.gz gcc-ba1e69c03f96f8f9f0e0d4218b168bf975a83cbb.tar.bz2 |
DR 374 - specialization in outer namespace
PR c++/56840
* pt.c (check_specialization_namespace): Allow any enclosing
namespace.
(check_unqualified_spec_or_inst): New.
(check_explicit_specialization): Call it.
* parser.c (cp_parser_elaborated_type_specifier)
(cp_parser_class_head): Call it.
From-SVN: r242348
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 3 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 2 | ||||
-rw-r--r-- | gcc/cp/parser.c | 37 | ||||
-rw-r--r-- | gcc/cp/pt.c | 67 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/explicit-inst1.C | 13 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/spec17.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/spec25.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/spec36.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.ns/template13.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/explicit73.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/lookup10.C | 4 |
13 files changed, 112 insertions, 42 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 678c44d..60186ee 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2016-11-12 Jason Merrill <jason@redhat.com> + + DR 374 + PR c++/56840 + * pt.c (check_specialization_namespace): Allow any enclosing + namespace. + (check_unqualified_spec_or_inst): New. + (check_explicit_specialization): Call it. + * parser.c (cp_parser_elaborated_type_specifier) + (cp_parser_class_head): Call it. + 2016-11-10 Jason Merrill <jason@redhat.com> PR c++/77337 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8183775..3e41a33 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6082,6 +6082,7 @@ extern void reset_specialization (void); extern void end_specialization (void); extern void begin_explicit_instantiation (void); extern void end_explicit_instantiation (void); +extern void check_unqualified_spec_or_inst (tree, location_t); extern tree check_explicit_specialization (tree, tree, int, int); extern int num_template_headers_for_class (tree); extern void check_template_variable (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 185c98b..6101504 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7868,8 +7868,7 @@ check_class_member_definition_namespace (tree decl) diagnostics. */ if (processing_specialization) return; - /* There are no restrictions on the placement of - explicit instantiations. */ + /* We check this in check_explicit_instantiation_namespace. */ if (processing_explicit_instantiation) return; /* [class.mfct] diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index e574c27..8db6cfd 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3558,7 +3558,7 @@ set_decl_namespace (tree decl, tree scope, bool friendp) /* Since decl is a function, old should contain a function decl. */ if (!is_overloaded_fn (old)) goto complain; - /* A template can be explicitly specialized in any namespace. */ + /* We handle these in check_explicit_instantiation_namespace. */ if (processing_explicit_instantiation) return; if (processing_template_decl || processing_specialization) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7b95dba..b3b69b3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -17004,24 +17004,28 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, globalscope = cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); /* Look for the nested-name-specifier. */ + tree nested_name_specifier; if (tag_type == typename_type && !globalscope) { - if (!cp_parser_nested_name_specifier (parser, + nested_name_specifier + = cp_parser_nested_name_specifier (parser, /*typename_keyword_p=*/true, /*check_dependency_p=*/true, /*type_p=*/true, - is_declaration)) + is_declaration); + if (!nested_name_specifier) return error_mark_node; } else /* Even though `typename' is not present, the proposed resolution to Core Issue 180 says that in `class A<T>::B', `B' should be considered a type-name, even if `A<T>' is dependent. */ - cp_parser_nested_name_specifier_opt (parser, - /*typename_keyword_p=*/true, - /*check_dependency_p=*/true, - /*type_p=*/true, - is_declaration); + nested_name_specifier + = cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/true, + /*check_dependency_p=*/true, + /*type_p=*/true, + is_declaration); /* For everything but enumeration types, consider a template-id. For an enumeration type, consider only a plain identifier. */ if (tag_type != enum_type) @@ -17069,8 +17073,18 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, else if (tag_type == typename_type && TREE_CODE (decl) != TYPE_DECL) ; else if (TREE_CODE (decl) == TYPE_DECL) - type = check_elaborated_type_specifier (tag_type, decl, - /*allow_template_p=*/true); + { + type = check_elaborated_type_specifier (tag_type, decl, + /*allow_template_p=*/true); + + /* If the next token is a semicolon, this must be a specialization, + instantiation, or friend declaration. Check the scope while we + still know whether or not we had a nested-name-specifier. */ + if (type != error_mark_node + && !nested_name_specifier && !is_friend + && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + check_unqualified_spec_or_inst (type, token->location); + } else if (decl == error_mark_node) type = error_mark_node; } @@ -22336,6 +22350,11 @@ cp_parser_class_head (cp_parser* parser, { type = TREE_TYPE (id); type = maybe_process_partial_specialization (type); + + /* Check the scope while we still know whether or not we had a + nested-name-specifier. */ + if (type != error_mark_node) + check_unqualified_spec_or_inst (type, type_start_token->location); } if (nested_name_specifier) pushed_scope = push_scope (nested_name_specifier); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d4855d5..d9499d9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -772,28 +772,29 @@ check_specialization_namespace (tree tmpl) /* [tmpl.expl.spec] - An explicit specialization shall be declared in the namespace of - which the template is a member, or, for member templates, in the - namespace of which the enclosing class or enclosing class - template is a member. An explicit specialization of a member - function, member class or static data member of a class template - shall be declared in the namespace of which the class template is - a member. */ + An explicit specialization shall be declared in a namespace enclosing the + specialized template. An explicit specialization whose declarator-id is + not qualified shall be declared in the nearest enclosing namespace of the + template, or, if the namespace is inline (7.3.1), any namespace from its + enclosing namespace set. */ if (current_scope() != DECL_CONTEXT (tmpl) && !at_namespace_scope_p ()) { error ("specialization of %qD must appear at namespace scope", tmpl); return false; } - if (is_associated_namespace (current_namespace, tpl_ns)) - /* Same or super-using namespace. */ + + if (cxx_dialect < cxx11 + ? is_associated_namespace (current_namespace, tpl_ns) + : is_ancestor (current_namespace, tpl_ns)) + /* Same or enclosing namespace. */ return true; else { permerror (input_location, "specialization of %qD in different namespace", tmpl); - permerror (DECL_SOURCE_LOCATION (tmpl), - " from definition of %q#D", tmpl); + inform (DECL_SOURCE_LOCATION (tmpl), + " from definition of %q#D", tmpl); return false; } } @@ -2586,6 +2587,36 @@ check_template_variable (tree decl) } } +/* An explicit specialization whose declarator-id or class-head-name is not + qualified shall be declared in the nearest enclosing namespace of the + template, or, if the namespace is inline (7.3.1), any namespace from its + enclosing namespace set. + + If the name declared in the explicit instantiation is an unqualified name, + the explicit instantiation shall appear in the namespace where its template + is declared or, if that namespace is inline (7.3.1), any namespace from its + enclosing namespace set. */ + +void +check_unqualified_spec_or_inst (tree t, location_t loc) +{ + tree tmpl = most_general_template (t); + if (DECL_NAMESPACE_SCOPE_P (tmpl) + && !is_associated_namespace (current_namespace, + CP_DECL_CONTEXT (tmpl))) + { + if (processing_specialization) + permerror (loc, "explicit specialization of %qD outside its " + "namespace must use a nested-name-specifier", tmpl); + else if (processing_explicit_instantiation + && cxx_dialect >= cxx11) + /* This was allowed in C++98, so only pedwarn. */ + pedwarn (loc, OPT_Wpedantic, "explicit instantiation of %qD " + "outside its namespace must use a nested-name-" + "specifier", tmpl); + } +} + /* Check to see if the function just declared, as indicated in DECLARATOR, and in DECL, is a specialization of a function template. We may also discover that the declaration is an explicit @@ -2949,15 +2980,8 @@ check_explicit_specialization (tree declarator, return error_mark_node; else { - if (!ctype && !was_template_id - && (specialization || member_specialization - || explicit_instantiation) - && !is_associated_namespace (CP_DECL_CONTEXT (decl), - CP_DECL_CONTEXT (tmpl))) - error ("%qD is not declared in %qD", - tmpl, current_namespace); - else if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_HIDDEN_FRIEND_P (tmpl)) + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_HIDDEN_FRIEND_P (tmpl)) { if (pedwarn (DECL_SOURCE_LOCATION (decl), 0, "friend declaration %qD is not visible to " @@ -2965,6 +2989,9 @@ check_explicit_specialization (tree declarator, inform (DECL_SOURCE_LOCATION (tmpl), "friend declaration here"); } + else if (!ctype && !is_friend + && CP_DECL_CONTEXT (decl) == current_namespace) + check_unqualified_spec_or_inst (tmpl, DECL_SOURCE_LOCATION (decl)); tree gen_tmpl = most_general_template (tmpl); diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit-inst1.C b/gcc/testsuite/g++.dg/cpp0x/explicit-inst1.C new file mode 100644 index 0000000..a6455d8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/explicit-inst1.C @@ -0,0 +1,13 @@ +// In C++11 explicit instantiation without a nested-name-specifier must be in +// the same namespace. + +namespace N { + template <class T> class foo {}; + template <class T> class bar {}; +} + +using N::bar; +template class bar<int>; // { dg-error "" "" { target c++11 } } + +using namespace N; +template class foo<int>; // { dg-error "" "" { target c++11 } } diff --git a/gcc/testsuite/g++.dg/template/spec17.C b/gcc/testsuite/g++.dg/template/spec17.C index 2375576..91c5d56 100644 --- a/gcc/testsuite/g++.dg/template/spec17.C +++ b/gcc/testsuite/g++.dg/template/spec17.C @@ -1,7 +1,7 @@ // PR c++/16224 namespace io { - template <typename> int foo(); // { dg-error "" } + template <typename> int foo(); } using namespace io; diff --git a/gcc/testsuite/g++.dg/template/spec25.C b/gcc/testsuite/g++.dg/template/spec25.C index 385d19a..d6f0f08 100644 --- a/gcc/testsuite/g++.dg/template/spec25.C +++ b/gcc/testsuite/g++.dg/template/spec25.C @@ -1,10 +1,10 @@ namespace N { template <typename T> struct S { - void f() {} // { dg-error "definition" } + void f() {} }; } namespace K { - template <> void N::S<char>::f() {} // { dg-error "different namespace" } + template <> void N::S<char>::f() {} // { dg-error "namespace" } } diff --git a/gcc/testsuite/g++.dg/template/spec36.C b/gcc/testsuite/g++.dg/template/spec36.C index 7e8dc52..5807fc5 100644 --- a/gcc/testsuite/g++.dg/template/spec36.C +++ b/gcc/testsuite/g++.dg/template/spec36.C @@ -8,9 +8,9 @@ struct basic_string namespace MyNS { class MyClass { template <typename T> - T test() { } /* { dg-error "from definition" } */ + T test() { } /* { dg-message "from definition" "" { target c++98_only } } */ }; } template <> -basic_string MyNS::MyClass::test() /* { dg-error "specialization of" } */ +basic_string MyNS::MyClass::test() /* { dg-error "specialization of" "" { target c++98_only } }*/ { return 1; } diff --git a/gcc/testsuite/g++.old-deja/g++.ns/template13.C b/gcc/testsuite/g++.old-deja/g++.ns/template13.C index a9559c71..e8e5304 100644 --- a/gcc/testsuite/g++.old-deja/g++.ns/template13.C +++ b/gcc/testsuite/g++.old-deja/g++.ns/template13.C @@ -4,7 +4,7 @@ namespace bar { // trick it to provide some prior declaration template<class T> - void foo(); // { dg-error "definition" } + void foo(); template<class T>class X; // { dg-message "note: previous declaration" } } @@ -15,7 +15,7 @@ bar::foo(T const &a) // { dg-error "" "" { xfail *-*-* } } not declared in b return a; } -template<> void bar::foo<int>() // { dg-error "different namespace" } +template<> void bar::foo<int>() // { dg-error "different namespace" "" { target c++98_only } } { } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C index 1d83e34..f8ceaf7 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C @@ -7,7 +7,7 @@ // the template namespace N { - template <class T> class foo; // { dg-error "" } referenced below + template <class T> class foo; } using namespace N; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C b/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C index 1c04250..9d2add8 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C @@ -13,8 +13,8 @@ namespace Outer { namespace Core = Core_Real; namespace Core_Real { - template<class T> void Foo (T *) {} // { dg-error "definition" } + template<class T> void Foo (T *) {} } - template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" } + template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" "" { target c++98_only } } } |