[REVISED PATCH][RFC] Fix PR c++/31923: Storage class with explicit template specialization
Simon Baldwin
simonb@google.com
Fri Jun 15 18:19:00 GMT 2007
Attached is a revised version of a pending patch first distributed as
http://gcc.gnu.org/ml/gcc-patches/2007-05/msg02033.html
The attached patch implements section 7.1.1-1 of the C++ standard by
preventing storage class specifiers on explicit specializations of templated
functions. It also adjusts the linkage of such explicit specializations that
now cannot specify a storage class so that they meet the recommendations of
the C++ Core Language Working Group for Defect Report 605:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#605
The patch includes two new tests, to verify parsing and linkage of explicit
specializations of templated functions.
Regression tested with the full g++ testsuite.
gcc/cp/ChangeLog
2007-06-15 Simon Baldwin <simonb@google.com>
PR c++/31923
* parser.c (cp_parser_single_declaration): Added check for storage
class other than sc_none in parsed declaration, and a flag to indicate
if the call is part of an explicit template specialization parse.
* (cp_parser_explicit_specialization): Specialization check flag added
to call to cp_parser_single_declaration(), set true.
* (cp_parser_template_declaration_after_export): Specialization check
flag added to call to cp_parser_single_declaration(), set false.
* pt.c (check_explicit_specialization): Added code to copy visiblity
and linkage from the templated function to the explicit specialization.
gcc/testsuite/ChangeLog
2007-06-15 Simon Baldwin <simonb@google.com>
PR c++/31923
* g++.dg/template/error25.C: New.
* g++.dg/template/spec35.C: New.
diff -Nrcp3 gcc_orig/gcc/cp/parser.c gcc/gcc/cp/parser.c
*** gcc_orig/gcc/cp/parser.c Tue Jun 12 10:21:25 2007
--- gcc/gcc/cp/parser.c Fri Jun 15 09:45:58 2007
*************** static void cp_parser_template_declarati
*** 1913,1919 ****
static void cp_parser_perform_template_parameter_access_checks
(VEC (deferred_access_check,gc)*);
static tree cp_parser_single_declaration
! (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
--- 1913,1919 ----
static void cp_parser_perform_template_parameter_access_checks
(VEC (deferred_access_check,gc)*);
static tree cp_parser_single_declaration
! (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
*************** cp_parser_explicit_specialization (cp_pa
*** 10225,10230 ****
--- 10225,10231 ----
cp_parser_single_declaration (parser,
/*checks=*/NULL,
/*member_p=*/false,
+ /*explicit_specialization_p=*/true,
/*friend_p=*/NULL);
/* We're done with the specialization. */
end_specialization ();
*************** cp_parser_template_declaration_after_exp
*** 16510,16515 ****
--- 16511,16517 ----
decl = cp_parser_single_declaration (parser,
checks,
member_p,
+ /*explicit_specialization_p=*/false,
&friend_p);
pop_deferring_access_checks ();
*************** static tree
*** 16575,16580 ****
--- 16577,16583 ----
cp_parser_single_declaration (cp_parser* parser,
VEC (deferred_access_check,gc)* checks,
bool member_p,
+ bool explicit_specialization_p,
bool* friend_p)
{
int declares_class_or_enum;
*************** cp_parser_single_declaration (cp_parser*
*** 16648,16660 ****
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|| decl_specifiers.type != error_mark_node))
! decl = cp_parser_init_declarator (parser,
! &decl_specifiers,
! checks,
! /*function_definition_allowed_p=*/true,
! member_p,
! declares_class_or_enum,
! &function_definition_p);
pop_deferring_access_checks ();
--- 16651,16677 ----
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|| decl_specifiers.type != error_mark_node))
! {
! decl = cp_parser_init_declarator (parser,
! &decl_specifiers,
! checks,
! /*function_definition_allowed_p=*/true,
! member_p,
! declares_class_or_enum,
! &function_definition_p);
!
! /* 7.1.1-1 [dcl.stc]
!
! A storage-class-specifier shall not be specified in an explicit
! specialization... */
! if (decl
! && explicit_specialization_p
! && decl_specifiers.storage_class != sc_none)
! {
! error ("explicit template specialization cannot have a storage class");
! decl = error_mark_node;
! }
! }
pop_deferring_access_checks ();
diff -Nrcp3 gcc_orig/gcc/cp/pt.c gcc/gcc/cp/pt.c
*** gcc_orig/gcc/cp/pt.c Tue Jun 12 10:21:25 2007
--- gcc/gcc/cp/pt.c Fri Jun 15 10:40:03 2007
*************** check_explicit_specialization (tree decl
*** 2193,2198 ****
--- 2193,2227 ----
TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl);
TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl);
+ /* 7.1.1-1 [dcl.stc]
+
+ A storage-class-specifier shall not be specified in an
+ explicit specialization...
+
+ The parser rejects these, so unless action is taken here,
+ explicit function specializations will always appear with
+ global linkage.
+
+ The action recommended by the C++ CWG in response to C++
+ defect report 605 is to make the storage class and linkage
+ of the explicit specialization match the templated function:
+
+ http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#605
+ */
+ if (tsk == tsk_expl_spec
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_TEMPLATE_INFO (decl) && DECL_USE_TEMPLATE (decl)
+ && DECL_FUNCTION_TEMPLATE_P (gen_tmpl))
+ {
+ tree tmpl_func = DECL_TEMPLATE_RESULT (gen_tmpl);
+ gcc_assert (TREE_CODE (tmpl_func) == FUNCTION_DECL);
+
+ /* This specialization has the same linkage and visiblity as
+ the function template it specializes. */
+ TREE_PUBLIC (decl) = TREE_PUBLIC (tmpl_func);
+ DECL_THIS_STATIC (decl) = DECL_THIS_STATIC (tmpl_func);
+ }
+
/* If DECL is a friend declaration, declared using an
unqualified name, the namespace associated with DECL may
have been set incorrectly. For example, in:
diff -Nrcp3 gcc_orig/gcc/testsuite/g++.dg/template/error25.C gcc/gcc/testsuite/g++.dg/template/error25.C
*** gcc_orig/gcc/testsuite/g++.dg/template/error25.C Wed Dec 31 16:00:00 1969
--- gcc/gcc/testsuite/g++.dg/template/error25.C Tue Jun 12 14:02:38 2007
***************
*** 0 ****
--- 1,16 ----
+ // PR c++/31923
+
+ template<class T>
+ static void f1 ();
+
+ template<>
+ static void f1<void> (); // { dg-error "explicit template specialization cannot have a storage class" }
+
+ template<class T>
+ extern void f2 ();
+
+ template<>
+ extern void f2<void> (); // { dg-error "explicit template specialization cannot have a storage class" }
+
+ export template<class T> // { dg-warning "keyword 'export' not implemented" }
+ static void* f3 ();
diff -Nrcp3 gcc_orig/gcc/testsuite/g++.dg/template/spec35.C gcc/gcc/testsuite/g++.dg/template/spec35.C
*** gcc_orig/gcc/testsuite/g++.dg/template/spec35.C Wed Dec 31 16:00:00 1969
--- gcc/gcc/testsuite/g++.dg/template/spec35.C Fri Jun 15 10:35:33 2007
***************
*** 0 ****
--- 1,29 ----
+ // PR c++/31923
+ // C++ DR 605 -- "...the linkage of an explicit specialization must be that of
+ // the template."
+
+ // { dg-do compile { target i?86-*-* x86_64-*-* } }
+ // { dg-require-weak "" }
+
+ template<class T>
+ static void f1 (T) { }
+
+ // { dg-final { scan-assembler-not ".glob(a|)l\[\t \]*_Z2f1IfEvT_" } }
+ template<>
+ void f1<float> (float) { } // Expected to have static linkage
+
+ template<class T>
+ void f2 (T) { }
+
+ // { dg-final { scan-assembler ".glob(a|)l\[\t \]*_Z2f2IfEvT_" } }
+ template<>
+ void f2<float> (float) { } // Expected to have global linkage
+
+ void instantiator ()
+ {
+ // { dg-final { scan-assembler-not ".glob(a|)l\[\t \]*_Z2f1IiEvT_" } }
+ f1(0); // Expected to have static linkage
+
+ // { dg-final { scan-assembler ".weak\[\t \]*_Z2f2IiEvT_" } }
+ f2(0); // Expected to have weak global linkage
+ }
More information about the Gcc-patches
mailing list